The exception handler for your Plaid integration. When the bank link fails, we collect the borrower's statement (popup or email) and return it in the exact Plaid schema you already parse. Verified, drop-in, pay only when it works.
1 // your existing flow, unchanged 2 try { 3 await plaid() 4 } catch (E) { 5 // live popup on your page... 6 await useBrook({ embed: true }) 7 // ...or async email link: 8 // useBrook({ email }) 9 } 10 // → identical Plaid schema. drop-in. ✓
Reads statements from
Brook does exactly one thing: handle the exception when Plaid can't connect. Pop our upload widget on your page or email the borrower a link, read the PDF, and return in the same call. No workflow, no rules engine, no chasing.
One flag picks the mode. embed: true drops the upload popup on your page while the borrower's still there. email sends a link for later. Same portal either way.
The email path doesn't time out. It waits. Minutes or days, Brook holds the request open and resolves it the moment the borrower uploads.
We don't even change the format. Output matches Plaid's exact data types, field for field. Your existing parser just works. Nothing downstream changes.
Every statement is checked at the source: document hash, tamper detection, line-level confidence. Not a guess, a verified read you can stand behind.
Turn it on per call and get a full provenance + audit certificate: where the data came from, how it was read, exportable for underwriting and compliance.
No seats, no subscription, no charge for a borrower who never replies. You pay when Brook returns verified data. That's it.
npm i brook and drop in your API key.
In your existing catch, call useBrook(): pass embed: true for a popup or email for a link. That's the whole integration.
Popup on your page or a one-click email link. The borrower drops their PDF, we parse it. The email path holds the call open until they do.
Normalized transactions return in the same request, in Plaid's exact schema. Your downstream logic doesn't change. You only pay for this step.
1 import { useBrook } from "brook" 2 3 // live popup, borrower's still on the page 4 const data = await useBrook({ embed: true }) 5 6 // or async: email a link, durable wait: 7 // useBrook({ email: borrower.email }) 8 9 // data.transactions[] in Plaid schema, 1:1 ✓
Brook isn't a new integration to design around. It's the fallback that fires in your existing catch block: same screen, same schema, same workflow. The borrower never knows the bank connection failed.
Bank link times out or fails. Your existing Plaid call throws, exactly like today.
Your catch calls useBrook(): drop our popup on the page, or email a link. Same portal.
Any bank, any format PDF. One drop. No account, no app, no back-and-forth.
We read the PDF and return it in Plaid's exact shape. Your downstream logic never knows the difference.
With embed: true the borrower never leaves your page. The upload popup renders right where Plaid failed. Bounced before finishing? The email mode catches them later. Same portal, same result.
No worries, we couldn't connect automatically. Drop your statement and we'll take it from here.
We handle the most sensitive document a person owns. So we hold it for exactly as long as the call runs, and not a second more.
Statements are processed in memory and purged the moment we return. Nothing persists on our side. Ever.
TLS 1.3 in transit, AES-256 at rest for the brief window of processing. Keys scoped per request.
Borrower documents are never used for training, never resold, never shared. Single purpose: your call.
Every access logged and attributable. Full audit export per borrower, per call, on demand.
No seats, no subscription, no minimums. You're billed only when Brook returns a verified statement in Plaid's schema.
embed) and email modesOne catch block. Popup or email. You only pay when it works.
try { plaid() } catch (E) { useBrook() }