Accounts Controllers
the cartridge extends sfra's account , address , and paymentinstruments controllers with server prepend / server append , and each extension calls the same fortercustomerupdate js pipelet used across every account event response actions for each outcome are configured on accounts configuration # extended routes customer action route extension forter call on decline log in account login prepend login logs the customer back out and returns the decline message sign up account submitregistration prepend + append signup deletes the account sfra just created and returns the decline message update profile (name, email, phone) account saveprofile prepend + append profile access (email/phone only) reverts the changed fields and returns the decline message change password account savepassword append profile access reverts the password and returns the decline message add or edit an address address saveaddress prepend profile access blocks the save and returns the decline message remove an address address deleteaddress prepend profile access blocks the delete (403) and returns the decline message add a payment method paymentinstruments savepayment prepend profile access blocks the save and returns the decline message remove a payment method paymentinstruments deletepayment prepend profile access blocks the delete (403) and returns the decline message profile access calls only fire for the fields that actually changed editing just a phone number doesn't trigger an email check, and saving a profile with no email/phone change doesn't call forter at all on a verification required decision, login and every profile access caller also report an authentication result back to forter ( forterauthenticationattemptupdate js ), tied to the decision's correlationid see accounts configuration # for what you still need to build to act on a verification required outcome signup declines reverse account creation sfra's base submitregistration creates the customer account before forter's appended handler runs on decline, the handler removes that same account ( customermgr removecustomer ) rather than preventing its creation up front the customer briefly exists mid request and is gone by the time the decline response is returned two different decline mechanisms saveprofile and savepassword revert an already committed change both use server append , so sfra's base logic runs and commits the new value first; forter's handler captures the previous value going in and, on decline, restores it savepassword 's implementation says this directly "base commits the new password inside its own beforecomplete so if forter declines we need the old password to roll the change back " saveaddress , deleteaddress , and deletepayment never let the change happen in the first place all three are server prepend hooks that check forter before calling next() on decline, the base save/delete logic never runs, so there's nothing to roll back either way, the customer sees the decline message and their account ends up exactly as it was before the request which declines render automatically, and which need a frontend change login , submitregistration , saveprofile , savepassword , saveaddress , and savepayment all return { success false, error \[ ] } base sfra's client side formvalidation() helper, already wired into each of these forms' ajax success handlers, renders that error array as an alert banner automatically no frontend change needed deleteaddress also renders automatically, through a different path its decline returns http 403, which base sfra's addressbook js ajax error handler catches and displays via createerrornotification(err responsejson errormessage) deletepayment is the exception its decline also returns http 403 with errormessage , but base sfra's paymentinstruments js error handler for removing a payment method only checks for a redirecturl — there's no fallback branch that displays errormessage a forter decline here fails silently unless you add one override removepayment in a cartridge ahead of app storefront base and add the missing branch error function (err) { if (err responsejson redirecturl) { window\ location href = err responsejson redirecturl; } else if (err responsejson errormessage) { // display err responsejson errormessage to the customer } $ spinner() stop(); } payment methods savepayment fully replaces the base route unlike every other row in the table above, paymentinstruments savepayment 's prepend never calls next() it reimplements card validation and instrument creation itself and always terminates the route directly, so sfra's base savepayment logic never runs this matters for psp cartridges that also take over payment saving if a psp tokenizes cards through its own route, bypassing paymentinstruments savepayment entirely, forter's controller hook never fires call the app payment saved hook from the psp's own flow instead hookshelper('app payment saved', 'paymentsaved', paymentdata, ); see example stripe payment element # for this applied in detail, and psp integration guide # for the equivalent pattern on the order side ( app post auth ) if a psp cartridge instead prepends paymentinstruments savepayment directly rather than using its own route, both prepends compete for the same unconditional termination only the one earlier in the cartridge path runs, and it's silent either way placing int forter sfra before any psp cartridge (see import cartridge # ) decides that order, but doesn't eliminate the risk; if the psp cartridge wins, add a call to the app payment saved hook from its flow so forter still sees the update