Jetpay Developer Guide
...
Payment iFrame (beta)
Security and Troubleshooting
27 min
security & troubleshooting security considerations api token management ✅ best practices environment variables store api tokens in environment variables, never in client side code separate environments use different tokens for development, staging, and production regular rotation rotate api tokens according to your security policy access control limit api token permissions to only what's necessary ❌ security anti patterns // ❌ never do this exposes token in client side code const api token = "jetpay live abc123 "; // ❌ never commit tokens to version control const config = { apitoken "jetpay test xyz789 ", }; // ✅ correct approach const api token = process env api token; token storage examples \# env file (never commit this) api token=jetpay live sk 1a2b3c4d5e6f7g8h9i0j \# for different environments api token dev=jetpay test sk dev123 api token staging=jetpay test sk staging456 api token prod=jetpay live sk prod789 origin validation production security always validate the origin of postmessage events in production function handlepaymentevents(event messageevent) { // list of allowed origins const allowedorigins = \[ "https //pay jetpay com", "https //checkout jetpay com", ]; if (!allowedorigins includes(event origin)) { console warn("rejected message from unauthorized origin ", event origin); return; } // process event only after validation processpaymentevent(event data); } development vs production function isvalidorigin(origin string) boolean { if (process env node env === "development") { // more permissive in development return origin includes("jetpay com") || origin === "http //localhost 3000"; } // strict validation in production const allowedorigins = \[ "https //pay jetpay com", "https //checkout jetpay com", ]; return allowedorigins includes(origin); } input validation amount validation function validateamount(amount string) number { // check if amount is provided if (!amount || amount trim() === "") { throw new error("amount is required"); } // convert to number const numamount = number(amount); // validate numeric value if (isnan(numamount)) { throw new error("amount must be a valid number"); } // check for positive value if (numamount <= 0) { throw new error("amount must be greater than zero"); } // check for reasonable maximum if (numamount > 1000000) { throw new error("amount exceeds maximum limit"); } // check for excessive decimal places if (amount includes(" ") && amount split(" ")\[1] length > 2) { throw new error("amount cannot have more than 2 decimal places"); } return numamount; } sanitization helper function sanitizeinput(input string) string { return input trim() replace(/\[^\d ]/g, "") // remove non numeric characters except and replace(/^ /, "") // remove leading minus replace(/\\ +/g, " ") // replace multiple dots with single dot replace(/^\\ /, "0 "); // add leading zero if starts with dot } troubleshooting common issues payment url generation fails symptoms api returns 401 unauthorized api returns 403 forbidden network errors during api calls solutions // check api token validity async function validateapitoken() { try { const response = await axios get("/auth/validate", { headers { authorization `bearer ${api token}` }, }); console log("✅ api token is valid"); return true; } catch (error) { if (error response? status === 401) { console error("❌ invalid api token"); } return false; } } // verify environment variables function checkenvironment() { const required = \["api token", "external api base url", "bank account"]; const missing = required filter((key) => !process env\[key]); if (missing length > 0) { console error("missing environment variables ", missing); return false; } return true; } events not received symptoms payment events don't trigger event listeners not firing silent failures solutions // debug event listener function debugeventlistener() { window\ addeventlistener("message", (event) => { console log("received message ", { origin event origin, data event data, timestamp new date() toisostring(), }); }); } // check iframe embedding function validateiframe(iframeelement htmliframeelement) { const checks = { src !!iframeelement src, dimensions iframeelement width && iframeelement height, visible iframeelement offsetparent !== null, loaded iframeelement contentdocument? readystate === "complete", }; console log("iframe validation ", checks); return object values(checks) every(boolean); } payment fees not displaying symptoms surcharge amount always shows as 0 fee information missing from ui incorrect total calculations solutions // debug debit response const { data debit } = await axios put("/debit", debitdata); console log("debit response ", { identifier debit identifier, amount debit amount, surcharge debit customer surcharge amount, currency debit currency, }); // handle missing surcharge gracefully const surchargeamount = debit? customer surcharge amount ?? 0; if (typeof surchargeamount !== "number") { console warn("invalid surcharge amount ", surchargeamount); setsurchargeamount(0); } else { setsurchargeamount(surchargeamount); } error monitoring error logging interface paymenterror { type "api error" | "validation error" | "network error" | "unknown error"; message string; context record\<string, any>; timestamp string; } function logpaymenterror(error error, context record\<string, any> = {}) { const paymenterror paymenterror = { type categorizeerror(error), message error message, context { context, useragent navigator useragent, url window\ location href, }, timestamp new date() toisostring(), }; // log to console in development if (process env node env === "development") { console error("payment error ", paymenterror); } // send to monitoring service in production if (process env node env === "production") { sendtomonitoring(paymenterror); } } function categorizeerror(error error) paymenterror\["type"] { if (axios isaxioserror(error)) { return "api error"; } if (error message includes("validation")) { return "validation error"; } if (error message includes("network")) { return "network error"; } return "unknown error"; } health checks export async function performhealthcheck() promise<{ status "healthy" | "unhealthy"; checks record\<string, boolean>; }> { const checks = { environment checkenvironment(), apiconnection await checkapiconnection(), tokenvalidity await validateapitoken(), }; const ishealthy = object values(checks) every(boolean); return { status ishealthy ? "healthy" "unhealthy", checks, }; } async function checkapiconnection() promise\<boolean> { try { await axios get("/health", { timeout 5000 }); return true; } catch { return false; } } performance optimization request optimization // implement request timeout const api = axios create({ timeout 10000, // 10 seconds headers { "cache control" "no cache", }, }); // add retry logic for failed requests async function createiframelinkwithretry( amount string, maxretries = 3 ) promise\<string> { let lasterror error; for (let attempt = 1; attempt <= maxretries; attempt++) { try { return await createiframelink(amount); } catch (error) { lasterror = error as error; if (attempt < maxretries) { const delay = math pow(2, attempt) 1000; // exponential backoff await new promise((resolve) => settimeout(resolve, delay)); console log( `retry attempt ${attempt} failed, retrying in ${delay}ms ` ); } } } throw lasterror!; } getting help support resources jetpay api reference complete api reference jetpay support contact contact the dev team directly before contacting support gather this information api token id (not the full token) error messages with timestamps request/response logs (sanitized) browser/environment details steps to reproduce the issue sample support request subject payment url generation failing api 500 error environment production api token id jetpay live abc123 error "failed to create checkout link request failed with status code 500" timestamp 2024 01 15t14 30 00z browser chrome 120 0 0 0 amount $25 00 steps to reproduce 1\ call createiframelink("25 00") 2\ api returns 500 error during debit creation 3\ error occurs consistently for amounts over $20 request id req xyz789 (if available) next steps congratulations! you now have a complete understanding of jetpay webdropin integration here are some recommended next steps test thoroughly with different payment amounts and scenarios implement monitoring and error tracking in production customize the ui to match your brand guidelines set up automated testing for the payment flow monitor payment success rates and optimize accordingly