Katkat

Design an Embeddable Pay by Bank Widget

PlaidSoftware Engineer · Onsite

Last updated

Design a secure, embeddable Pay by Bank frontend widget and supporting backend infrastructure that enables direct bank checkout via an isolated iframe and asynchronous payment processing.

Scenario

You are designing a merchant-facing Pay by Bank embeddable widget for a financial technology platform. Merchants embed a lightweight JavaScript SDK on their checkout pages. When a user chooses to pay with their bank account, the SDK renders an isolated iframe modal where the user searches for their financial institution, authenticates, and authorizes a bank transfer (such as ACH, RTP, or FedNow) without exposing their bank credentials or account details to the merchant.

Requirements

Functional

  • Session Initialization: Merchant backend creates a single-use, short-lived session token (e.g., link_token) bound to the checkout amount, currency, and merchant identity.
  • Secure Widget Lifecycle: The client-side SDK instantiates an iframe pointing to a hosted auth domain, establishes a secure two-way communication channel, and surfaces events (e.g., onSuccess, onExit, onError).
  • Payment Authorization & Token Exchange: The widget securely captures user consent, completes bank OAuth or credential handoffs, and issues a short-lived authorization code to exchange on the merchant backend for a reusable or single-use payment token.
  • Asynchronous Payment State: Support payment rails where final settlement takes minutes (RTP/FedNow) to multiple business days (ACH), notifying merchants via webhooks.

Non-Functional & Security

  • Strict Secret Boundaries: Bank credentials, account numbers, and internal auth tokens must never leak to the merchant's DOM or network log.
  • Browser Security: Mitigate clickjacking, cross-site scripting (XSS), and origin spoofing across parent-to-iframe communication.
  • Resilience & Idempotency: Safe retry behavior for network dropouts, interrupted OAuth redirects, and duplicate clicks.
  • Availability & Latency: 99.99% uptime; iframe cold load time under 500ms.

Scale Assumptions

  • Peak traffic: 10,000 widget load requests per second; 500 completed authorizations per second.
  • Over 5,000 integrated merchants and 100 million total linked bank accounts.

What to Cover

  1. End-to-End Flow & APIs: Trace requests from merchant backend, merchant client DOM, iframe widget, your platform backend, and third-party bank APIs.
  2. Security & Browser Isolation: Explain window.postMessage handshake, origin validation, Content Security Policy (CSP), iframe sandboxing attributes, and OAuth redirect strategies.
  3. Data Model & State Machine: Define the payment session and transaction lifecycle states, including failure and dispute handling.
  4. Reliability & Observability: Mechanism for tracking funnel drop-offs, telemetry without PII leakage, and webhook delivery guarantees.

Hints

Hint 1

Ensure the postMessage protocol mandates that both the parent SDK and the child iframe strictly verify `event.origin` before reading payloads or sending sensitive responses.

Hint 2

Decouple client-side completion events from backend settlement by returning an exchangeable public token rather than an authorized payment object.

Hint 3

Consider how bank OAuth redirects interact with iframes, specifically why top-level browser redirects or popup windows are often required due to frame-busting headers.

Follow-up questions

  • How do you handle banks that set `X-Frame-Options: DENY` or refuse to load their login pages inside an iframe during OAuth flows?
  • If a user closes the browser tab after completing bank MFA but before the iframe sends `onSuccess` to the merchant page, how does the merchant know the payment was authorized?
  • How would you prevent a compromised merchant website from tampering with the payment amount or intercepting the postMessage channel?