Jetpay Developer Guide
...
Payment iFrame (beta)
Events and Fees
19 min
event handling & payment fees event handling overview the jetpay webdropin iframe communicates with your application through the window\ postmessage api implementing proper event handling is crucial for providing real time payment status updates available events event description when it occurs card payment setup payment interface is initializing when iframe loads and payment form appears card payment completed payment processed successfully when payment is confirmed and processed card payment failed payment attempt failed when payment is declined or fails validation card payment error technical error occurred when system errors occur during processing implementation example basic event listener import { useeffect } from "react"; export function paymentcomponent() { useeffect(() => { function handlepaymentevents(event messageevent) { // security validate origin in production // if (event origin !== 'https //pay jetpay com') return; switch (event data type) { case "card payment setup" handlepaymentsetup(event data); break; case "card payment completed" handlepaymentcompleted(event data); break; case "card payment failed" handlepaymentfailed(event data); break; case "card payment error" handlepaymenterror(event data); break; default console log("unknown payment event ", event data type); } } window\ addeventlistener("message", handlepaymentevents); return () => { window\ removeeventlistener("message", handlepaymentevents); }; }, \[]); // component jsx } event handler functions function handlepaymentsetup(data any) { // show loading state, prepare ui setpaymentstatus("initializing"); setloading(true); // optional track analytics analytics track("payment initialized", { amount data amount, timestamp date now(), }); } function handlepaymentcompleted(data any) { // handle successful payment setpaymentstatus("completed"); setloading(false); // update order status, redirect to success page updateorderstatus(data transactionid, "paid"); // show success message showsuccessmessage("payment completed successfully!"); // optional redirect after delay settimeout(() => { window\ location href = "/order confirmation"; }, 2000); } function handlepaymentfailed(data any) { // handle payment failure setpaymentstatus("failed"); setloading(false); // show error message, allow retry showerrormessage(data message || "payment failed please try again "); // log failure for analytics console error("payment failed ", data); } function handlepaymenterror(data any) { // handle technical errors setpaymentstatus("error"); setloading(false); // log error, notify support team console error("payment error ", data); // show user friendly error showerrormessage("a technical error occurred please contact support "); // optional send error to monitoring service errorreporting captureexception(new error(data message)); } payment status management state management with react import { usestate, usecallback } from "react"; type paymentstatus = "idle" | "initializing" | "completed" | "failed" | "error"; export function usepaymentstatus() { const \[status, setstatus] = usestate\<paymentstatus>("idle"); const \[message, setmessage] = usestate\<string>(""); const updatestatus = usecallback( (newstatus paymentstatus, newmessage = "") => { setstatus(newstatus); setmessage(newmessage); }, \[] ); return { status, message, updatestatus, isloading status === "initializing", iscompleted status === "completed", haserror status === "failed" || status === "error", }; } using the hook export function paymentcomponent() { const { status, message, updatestatus, isloading, iscompleted, haserror } = usepaymentstatus(); const handlepaymentevents = usecallback( (event messageevent) => { switch (event data type) { case "card payment setup" updatestatus("initializing", "preparing payment "); break; case "card payment completed" updatestatus("completed", "payment successful!"); break; case "card payment failed" updatestatus("failed", event data message || "payment failed"); break; case "card payment error" updatestatus("error", "technical error occurred"); break; } }, \[updatestatus] ); // rest of component } payment fees and surcharges when creating a debit, the jetpay api may return a customer surcharge amount representing additional payment processing fees handling surcharge amounts export async function createiframelink(amount string) promise<{ url string; surchargeamount number; }> { try { // contact and debit creation const { data debit } = await axios put("/debit", { amount number(amount), // other debit properties }); // extract surcharge amount const surchargeamount = debit? customer surcharge amount ?? 0; const transactionresponse = await axios post( `/transaction/${debit identifier}/pay debit/url` ); return { url transactionresponse data url, surchargeamount, }; } catch (error) { console error("failed to create checkout link ", error); throw error; } } fee display component interface feedisplayprops { subtotal number; surchargeamount number; } export function feedisplay({ subtotal, surchargeamount } feedisplayprops) { const total = subtotal + surchargeamount; return ( \<div classname="fee breakdown"> \<div classname="fee line"> \<span>subtotal \</span> \<span>${subtotal tofixed(2)}\</span> \</div> {surchargeamount > 0 && ( \<div classname="fee line processing fee"> \<span>processing fee \</span> \<span>${surchargeamount tofixed(2)}\</span> \</div> )} \<div classname="fee line total"> \<strong> \<span>total \</span> \<span>${total tofixed(2)}\</span> \</strong> \</div> \</div> ); } dynamic fee updates export function paymentcomponent() { const \[amount, setamount] = usestate\<number>(0); const \[surchargeamount, setsurchargeamount] = usestate\<number>(0); const \[iframeurl, setiframeurl] = usestate\<string>(""); const handlecreatepayment = async (baseamount number) => { try { const { url, surchargeamount } = await createiframelink( baseamount tostring() ); setamount(baseamount); setsurchargeamount(surchargeamount); setiframeurl(url); } catch (error) { console error("payment creation failed ", error); } }; return ( \<div classname="payment container"> \<feedisplay subtotal={amount} surchargeamount={surchargeamount} /> {iframeurl && \<iframe src={iframeurl} width="100%" height="600" />} \</div> ); } best practices for fee transparency ✅ do's display fees upfront show any additional charges in your order summary before payment update totals dynamically recalculate totals when fee information becomes available clear communication use descriptive labels like "processing fee" or "payment method fee" consistent formatting always show fees in the same currency format as the main amount ❌ don'ts don't hide fees until the last moment don't use vague terms like "additional charges" don't forget to include fees in the total calculation don't display fees that are zero or null advanced event handling event data validation interface paymenteventdata { type string; transactionid? string; amount? number; message? string; timestamp? number; } function validateeventdata(data any) data is paymenteventdata { return ( typeof data === "object" && typeof data type === "string" && \[ "card payment setup", "card payment completed", "card payment failed", "card payment error", ] includes(data type) ); } function handlepaymentevents(event messageevent) { if (!validateeventdata(event data)) { console warn("invalid payment event data ", event data); return; } // process validated event } next steps learn about security considerations and troubleshooting common issues continue to security and troubleshooting docid\ ynh2mxw9pit9e6vdkdngv >