Embed Paytool flows on your site. This SDK exposes a small, focused API on window.Paytool
for easy integration.
Add the SDK to your page:
<script src="https://paytool.verestro.com/v1/paytool.js"></script>
This creates a global window.Paytool
object with the following methods:
embedCardForm(options)
isEmbedError(err)
Note (CORS/allowlist): Your domain must be allowlisted for the SDK and hosted pages to load. See the full guidelines at https://developer.verestro.com or contact support to request an allowlist update.
Tip: Staging requires separate credentials. The environment may change more frequently; occasional instability can occur.
All examples below assume the SDK has been loaded and window.Paytool
is available.
Embeds a secure card form (iframe) you can style and control. Returns a CardFormEmbed
instance once the form is fully rendered and sized.
Signature:
Paytool.embedCardForm(options: CardFormEmbedOptions): Promise<CardFormEmbed>
CardFormEmbedOptions
and defaults:
interface CardFormEmbedOptions {
target: HTMLElement; // required
// Provide full PaymentMethods payload (as returned by /payment-methods).
// Strongly recommended. If omitted or null, the legacy token-only flow is used,
// which is deprecated and will be removed in a future version.
paymentMethods?: PaymentMethods | null;
optionalElements?:
| boolean
| {
firstNameField?: boolean; // default: true
lastNameField?: boolean; // default: true
emailField?: boolean; // default: true
cedulaField?: boolean; // default: false
storeField?: boolean; // default: true
transactionAgreement?: boolean; // default: true
dccInfo?: boolean; // default: true
cardNetworksInfo?: boolean; // default: true
submitLoader?: boolean; // default: true
};
onSubmit?: (state: CardFormEmbedState) => void; // default: no-op
onFormStateChange?: (state: CardFormEmbedState) => void; // default: no-op
onCardNumberChange?: (e: { token: string | null } | CardNumberInfo) => void; // default: no-op
// Note: The `{ token }` shape is deprecated and will be removed in a future version.
// Provide `paymentMethods` to receive a `CardNumberInfo` payload instead.
}
onCardNumberChange payload shape:
paymentMethods
): { token: string | null }
— token
is null
while the number is invalid.
Deprecated: The token
-only payload will be removed in a future release. Use CardNumberInfo
instead
by passing paymentMethods
and relying on cardNumberInfo
/paymentMethodData
in CardFormEmbedState
.CardNumberInfo
—type: 'STORED_PAYMENT_METHOD'
includes { id: string; encryptedCardNumber: null }
type: 'ENCRYPTED_CARD_NUMBER'
includes { encryptedCardNumber: string; id: null }
Example: preloading saved payment methods
// Fetch available payment methods for the user
const paymentMethodsFromServer = await getPaymentMethodsFromYourServer();
// Pass the whole object to the SDK; the card form will use the 'CARD' entry
const form = await Paytool.embedCardForm({
target: document.getElementById('card-form')!,
paymentMethods: paymentMethodsFromServer,
optionalElements: true
});
Helper example: getPaymentMethodsFromYourServer
// Example only — call your backend to fetch available methods for the current user.
// The endpoint should return the full `PaymentMethods` payload expected by the SDK.
async function getPaymentMethodsFromYourServer() {
const res = await fetch('/api/payment-methods', { credentials: 'include' });
if (!res.ok) throw new Error('Failed to fetch payment methods');
return res.json();
}
Example response shape returned by your backend:
{
"paymentMethods": [
{
"type": "CARD",
"storedPaymentMethodData": [
{
"type": "CARD",
"id": "693f3244-9919-49ba-91c8-b095a5cf2ffb",
"maskedCardNumber": "************9507",
"expirationDate": "12/26",
"cvcRequiredForPayment": false,
"cardBrand": "MASTERCARD",
"paymentMethodDataOwner": { "name": "Jan Kowal" }
}
]
}
]
}
CardFormEmbed
main methods and events:
pay(transactionId: string): Promise<EmbedPayResult>
— disables the form and begins payment.getFormState(): Promise<CardFormEmbedState>
— current validity, selected method, sender data, etc.enable()
/ disable()
— control interactivity.destroy()
— unmount the component.statechange
, cardnumberchange
, submit
(see Events section).Typical flow:
<div id="card-form"></div>
<script>
(async () => {
// 0) Get payment methods from server
const paymentMethodsFromServer = await getPaymentMethodsFromYourServer();
// 1) Embed the form
const cardForm = await Paytool.embedCardForm({
target: document.getElementById('card-form'),
optionalElements: true,
paymentMethods: paymentMethodsFromServer,
onFormStateChange: s => {
// s.isValid; s.token (deprecated); s.paymentMethodData; s.senderData; s.cardNumberInfo
},
onCardNumberChange: payload => {
if ('token' in payload) {
// Deprecated path (no payment methods): payload is { token }
const { token } = payload;
} else {
// Prefer using CardNumberInfo by providing `paymentMethods`.
console.log(payload);
}
}
});
// 2) When ready to charge (e.g., submit button), get latest state if needed
const state = await cardForm.getFormState();
const payload = state; // choose what your backend expects
// 3) Create a transaction on your server using the data above
const transactionId = await createTransactionOnYourServer(payload);
// 4) Start the payment
try {
const res = await cardForm.pay(transactionId);
console.log('Payment complete:', res.status);
} catch (err) {
if (!Paytool.isEmbedError(err)) throw err;
console.log('Payment failed:', err.status, err.reason);
}
})();
async function createTransactionOnYourServer(payload) {
// Example only: call your backend. Never handle charges purely on the client.
return '12345678-transaction-id';
}
</script>
Type guard that returns true
if the error originated from the SDK (EmbedError
). Useful when distinguishing SDK errors from unexpected script errors.
if (Paytool.isEmbedError(err)) {
console.log(err.status, err.reason);
}
Every callback in CardFormEmbedOptions
has a matching DOM event on the CardFormEmbed
element. This is handy if you prefer standard listeners over passing callbacks upfront.
statechange
— payload: CardFormEmbedState
cardnumberchange
— payload:{ token: string | null }
Deprecated: will be removed in a future release. Provide paymentMethods
to receive CardNumberInfo
.CardNumberInfo
(new card typing or saved card selection)submit
— payload: CardFormEmbedState
Example:
const form = await Paytool.embedCardForm({ target: el });
form.addEventListener('statechange', e => console.log(e.detail));
form.addEventListener('cardnumberchange', e => console.log(e.detail));
form.addEventListener('submit', e => console.log(e.detail));
The card form is rendered inside an iframe and sets its height dynamically after it finishes initial rendering. The element gets an initialized
CSS class at that moment — use it for layout styles to avoid a brief empty gap during first paint.
verestro-paytool-card-form-embed.initialized {
display: block;
background: #f3f4f6;
border: 2px solid #e8e8e8;
border-radius: 4px;
padding: 25px 28px 28px;
}
await cardForm.pay(...)
in try/catch
and use isEmbedError
to branch between SDK errors and unexpected ones.For end‑to‑end integration guidance (backend setup, redirect URLs, and merchant onboarding), see https://developer.verestro.com.