Implementation best practices
Origin validation, session timeouts, error handling, and responsive layout.
Implement proper origin validation
Always validate that postMessage events come from the form's expected origin to prevent malicious scripts from sending fake transaction results.
The form is served from a different host than the API. The session URL returned when you create the session (for example https://hpf.integratedcommerce.io/session/01JSFAMY0AGW27QKP30C727512) is the authoritative source for the origin to expect - derive it from that URL rather than hard-coding a host, so the same code works in sandbox and production.
// Derive the expected origin from the session URL the API returned.
const expectedOrigin = new URL(session.iframeUrl).origin;
const paymentFrame = document.querySelector("#payment-frame");
window.addEventListener("message", (event) => {
if (event.origin !== expectedOrigin) return;
if (!paymentFrame || event.source !== paymentFrame.contentWindow) return;
if (event.data?.type !== "hostedPaymentFormResult") return;
const result = event.data.data;
if (!result || typeof result !== "object") return;
handleTransactionResult(result);
});
Compare event.origin with a strict equality check against a full origin. Do not use endsWith, includes, or a regular expression on the origin - https://hpf.integratedcommerce.io.attacker.example ends with nothing suspicious to a substring test.
Handle timeouts gracefully
Sessions expire 10 minutes after creation, at the returned expirationTimestamp. Customer activity does not extend the session. Handle the error channel for your integration; the code can differ between a failed session load and an expired active session. A browser redirect or callback is not guaranteed if the page is closed.
The SDK session can be loaded once. Opening it again, refreshing the page, or mounting the same sessionId twice can fail even before expiry. Before creating a replacement session, reconcile any earlier payment submission. A new session-creation request returns a new iframe URL and sessionId.
Handle every response status
Your implementation should handle various response statuses, including:
- Successful payments (
resultCode = 0) - Declined transactions
- Expired sessions
- Processing errors
When processing errors occur or transaction status is uncertain, use the GET /transactions (List Transactions) endpoint to verify the final transaction outcome before retrying or taking corrective action. See Retrieving transactions.
Verify the redirect hash
If you use returnUrl, verify the HMAC hash on every redirect before acting on the parameters. See Verifying the redirect.
Test with the test cards
Use the published test cards during your integration development. The set includes approved cards plus cards that produce specific declines and processing errors, so you can exercise your error paths rather than only the happy path. See Test cards.
Responsive design
Ensure your payment page layout accommodates the iframe appropriately on all devices. The form itself is responsive and works on mobile, tablet, and desktop.
Before you go live
Certification requires two example transactions per applicable scenario, plus evidence of your success, decline, and error messaging. Building those paths now saves a round trip later - see Certification.