Agent Runbook - v6 Migration
You are a coding agent migrating a merchant codebase from @payrails/web-sdk
5.x to 6.x. This runbook tells you how to detect what needs migrating, route
each finding to the right instructions, execute the changes, and verify the
result. The detailed before/after for every breaking change lives in the
migration guide — this document routes you through it; it
does not repeat it. If you are a human, read the migration guide directly.
Ground rules
- Detect, don't assume. Determine the installed SDK version and the APIs
actually used from the codebase — not from what the user or this document's
age implies. - The installed package is the contract. When this runbook or any doc
disagrees with the TypeScript types shipped in the installed
@payrails/web-sdk, the types win. Never invent an API: before writing a call
you have not seen in the codebase, confirm it exists in the package's.d.ts
or in the reference docs. - Minimal diffs. Change only what the migration requires. Do not refactor,
rename, or restyle surrounding code. - Preserve behavior. Every v5 callback's logic must land in an equivalent v6
handler — count the callbacks you removed and the listeners you added, and
reconcile any difference. - Escalate, don't skip. Anything in the
escalate to a human list must be reported, not
silently dropped.
Phase 0 — Detect
- Read the installed version of
@payrails/web-sdkfrom the lockfile (or
node_modules/@payrails/web-sdk/package.json; fall back to the
package.jsonrange). - Route:
- 5.x — run the full migration below.
- 6.x — a migration may have been left incomplete. Run
Phase 1 anyway; fix whatever it still finds. - 4.x or older — stop and escalate; this runbook only covers 5 → 6.
- Not installed / loaded from a script tag — stop and escalate; this
runbook covers the npm package only.
Phase 1 — Inventory
First scope the search: limit every pattern below to files that import or
reference @payrails/web-sdk, plus the local modules that build option objects
for its calls. Names like onChange, onFocus, or onSuccess are ubiquitous
in frontend code — unscoped matches outside the SDK integration are false
positives, not work items.
Search the scoped files for each pattern (also match minor formatting variants).
Every hit is a work item; the section column links to the instructions.
| # | Search for | Meaning | Fix per |
|---|---|---|---|
| 1 | Payrails.init( | Init calls that must become awaited | guide §1 |
| 2 | payrails-styles.css | CSS import that no longer resolves | guide §1 |
| 3 | preloadCardForm | Removed static method | guide §2 |
| 4 | onClientInitialized | Argument/helper changes inside handler | guide §3 |
| 5 | events: inside options of dropin(, cardForm(, paymentButton(, googlePayButton(, applePayButton(, paypalButton(, leanButton(, genericRedirectButton(, dynamicElement( | Removed callback bags | guide §4 |
| 6 | onAuthorizeSuccess, onAuthorizeFailed, onAuthorizePending, onSuccess, onFailed, onPending, onRequestStart, onButtonClicked, onPaymentButtonClicked, onThreeDSecureChallenge, onDeliveryAddressChanged, onSessionExpired, onPaymentSessionExpired | Instance-level bag callbacks | guide §4 tables |
| 7 | onChange, onFocus, onReady, onValidate, onValidationChange, onStateChanged, onSaveInstrumentCheckboxChanged, onPreferredSchemeChanged, onBillingAddressChanged, onPaymentOptionSelected (in Payrails element options) | Element-level bag callbacks | guide §4 tables |
| 8 | onGooglePayAvailable, onApplePayAvailable, onPaypalAvailable | Availability callbacks → promise | guide §5 |
| 9 | styles: inside options of cardForm(, paymentButton(, dropin(, cardList(, dynamicElement(, genericRedirectButton(, leanButton(, collectContainer( | Structured styles → appearance | guide §6 |
| 10 | inputStyles, labelStyles, errorTextStyles | Dead collect-element style fields | guide §6 |
| 11 | PayrailsContainerType, containerType | Removed type / option | guide §7 |
Do not flag these — they are unchanged or correct in v6:
styleson standalonegooglePayButton/applePayButton/paypalButton
(provider chrome), and underpaymentMethodsConfiguration.<method>.styles.events: { onClientInitialized }atPayrails.init— the one surviving bag
callback (the handler body may still need item 4).- Existing
.on(...)subscriptions,setSavedInstrument,setState,
payrails.api(...),translations,fonts.
Also check the deployment configuration: if the site sets a
Content-Security-Policy, assets.payrails.io must be allowed in script-src
and style-src. You usually cannot change this yourself — escalate it.
Phase 2 — Execute
Work in this order; run the project's type-check after each step so regressions
localize to the step that caused them.
- Upgrade the dependency to
@payrails/web-sdk@6with the project's
package manager. - Make init awaited (inventory 1): add
await, propagate async up through
the callers, and add rejection handling forPAYRAILS_INIT_FAILEDwhere
other init errors are handled. In SSR frameworks, ensure the call runs only
in the browser (guide §1). - Delete the CSS import (inventory 2) and any bundler config that
referenced it. - Delete
preloadCardForm()calls (inventory 3). - Update
onClientInitializedhandler bodies (inventory 4): the argument
is the plain response object; helper calls move to thepayrailsinstance
per
guide §3. - Replace event bags with
.on()(inventory 5–7) using the mapping tables
in
guide §4.
Three semantic traps — a mechanical rename is NOT enough:- Boolean-return gates (
onRequestStart,onButtonClicked,
onDeliveryAddressChanged) must callevent.preventDefault(); a thrown
error no longer blocks the payment. - Payment-outcome listeners are session-wide. If the page mounts more than
one payment element, addevent.paymentMethodCode/event.actionfilters
to reproduce the old per-element behavior. failedpayloads carry the error inevent.data(e.data?.code), not at
the top level.
- Boolean-return gates (
- Replace availability callbacks (inventory 8) with
await button.isAvailable
(guide §5). - Migrate styling (inventory 9–10) to
appearanceusing the per-element
mapping tables in guide §6.
Translate each v5 style key via the tables; do not guess selectors. Watch the
three special cases: drop-in wallet-button chrome moves to
paymentMethodsConfiguration.<method>.styles, Revolut Pay uses
revolutOptions, the Lean dialog usesdialogCustomization. - Clean up types (inventory 11) per
guide §7.
Phase 3 — Verify
- Re-run the Phase 1 inventory. Items 1–11 must return no unmigrated hits
(modulo the do-not-flag list). - Type-check and build the project; both must pass.
- Runtime smoke test, if you can run the app: load the checkout page and
confirmPayrails.initresolves (bundle and stylesheet load from
assets.payrails.io), the payment elements render styled, and no
PAYRAILS_INIT_FAILEDerror appears in the console. - Report to the human: version migrated from/to, work items found and fixed
per inventory row, behavior-affecting choices you made (e.g. where you added
paymentMethodCodefilters), and every escalation item below that applies.
Escalate to a human
Report these instead of deciding yourself:
- CSP changes —
assets.payrails.ioinscript-src/style-srcis usually
infrastructure config outside the repo. - Visual sign-off — v6 ships a redesign
(guide §8); a human must approve
the new look and any re-created custom styling. - Real payment verification — completing a test payment in the
TEST
environment, 3DS challenges, wallet sheets, and session-expiry refresh need a
human (or explicit instruction) to exercise. - Ambiguous event logic — if a v5 callback's body encoded per-element
assumptions you cannot confidently reproduce with filters, show both versions
and ask.
Reference map
- Migration guide — every breaking change with before/after
code. Your primary instruction source. - Payrails class reference — option types,
methods, exports. - Events reference — every event with
payload types and cancelation semantics. - Migration guide §6 — the
authoritativestyles→appearancemapping. - Appearance reference — the
appearancetypes, rule semantics, and per-element class contract. - Getting started — hub for the remaining how-to
guides.
Updated 3 days ago