Tokenize-first shape: resolves with requires_confirmation plus the
APPROVED ORDER ID as clientToken — the host passes it to the server's
completePayment (
Dynamic script/SDK load — only pulled in if this PSP is active.
Renders paypal.Buttons into container. options.clientSecret is the
server-created order id. Button styling passes through untouched via
options.fieldOptions (style, fundingSource, …; options.appearance
is the style fallback) — the adapter owns ONLY the protected keys
createOrder / onApprove / onCancel / onError, because they ARE
the integration.
PayPal's popup can only be opened by PayPal's own rendered button (the click must originate inside their iframe), so for PayPal the rendered button IS the approval step: the buyer clicks it, approves in the popup ("Continue"), and
onChange({ complete: true })fires. PayFanout's own Pay button then runs confirm() -> completePayment on the server, which is where the money actually moves.