/** * One-off script to test BoA CashPro sandbox API connectivity. * Reads credentials from SSM Parameter Store, exchanges them for * OAuth Bearer tokens, then makes test API calls to both Check * Management and Reporting APIs. * * Prints full responses so you can capture the client ID, timestamp, * and transactionIdentification for BoA production onboarding. * * Usage: * node scripts/test-boa-sandbox.js */ import { SSMClient, GetParameterCommand } from "@aws-sdk/client-ssm"; const ssm = new SSMClient(); const SANDBOX_BASE = "https://api-sb.bofa.com"; const AUTH_URL = `${SANDBOX_BASE}/authn/v1/client-authentication`; async function getSSMParam(name) { const { Parameter } = await ssm.send( new GetParameterCommand({ Name: name, WithDecryption: true }) ); return Parameter.Value; } async function getAccessToken(applicationID, clientId, clientSecret) { console.log(` Requesting token for ${applicationID}...`); const res = await fetch(AUTH_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ applicationID, authn: { client_id: clientId, client_secret: clientSecret, }, }), }); const text = await res.text(); console.log(` Auth response (${res.status}):`, text, "\n"); if (!res.ok) { throw new Error(`Auth failed for ${applicationID}: ${res.status} - ${text}`); } const data = JSON.parse(text); return data.access_token; } async function main() { console.log("Loading credentials from SSM...\n"); const [ checkMgmtClientId, checkMgmtSecret, accountInfoClientId, accountInfoSecret, accountNumber, companyId, ] = await Promise.all([ getSSMParam("/payments-dashboard/boa-check-mgmt-client-id"), getSSMParam("/payments-dashboard/boa-check-mgmt-token"), getSSMParam("/payments-dashboard/boa-account-info-client-id"), getSSMParam("/payments-dashboard/boa-account-info-token"), getSSMParam("/payments-dashboard/boa-account-number"), getSSMParam("/payments-dashboard/boa-company-id"), ]); console.log("Credentials loaded.\n"); // --- Step 1: Get OAuth tokens for both APIs --- console.log("=".repeat(60)); console.log("STEP 1: OAuth Token Exchange"); console.log("=".repeat(60)); console.log("\n[Check Management]"); const checkMgmtBearerToken = await getAccessToken( "app_SeaHavenIndustries_Checkmanagement_SB", checkMgmtClientId, checkMgmtSecret ); console.log("[Account Info / Reporting]"); const accountInfoBearerToken = await getAccessToken( "app_SeaHavenIndustries_Reporting_SB", accountInfoClientId, accountInfoSecret ); console.log("Both tokens acquired.\n"); // --- Step 2: Check Issue (add_Issue with a test check) --- console.log("=".repeat(60)); console.log("TEST 1: Check Issue (add_Issue)"); console.log("=".repeat(60)); const issuePayload = { issueList: [ { accountNumber, issueAction: "add_Issue", checkNumber: "999999", amount: "1.00", issueDate: new Date().toISOString().split("T")[0], payee: "Sandbox Test", }, ], }; console.log("Request:", JSON.stringify(issuePayload, null, 2), "\n"); try { const issueRes = await fetch( `${SANDBOX_BASE}/cashpro/checkmanagement/v1/check-issues`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${checkMgmtBearerToken}`, companyId, }, body: JSON.stringify(issuePayload), } ); const issueHeaders = Object.fromEntries(issueRes.headers.entries()); const issueText = await issueRes.text(); console.log("Status:", issueRes.status); console.log("Response Headers:", JSON.stringify(issueHeaders, null, 2)); console.log("Response Body:", issueText); } catch (err) { console.error("Check Issue request failed:", err.message); } // --- Step 3: Previous Day Transaction Inquiry --- console.log("\n" + "=".repeat(60)); console.log("TEST 2: Previous Day Transaction Inquiry"); console.log("=".repeat(60)); const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); const dateStr = yesterday.toISOString().split("T")[0]; const inquiryPayload = { fromDate: dateStr, toDate: dateStr, accounts: [ { accountNumber, bankId: "021000322", }, ], }; console.log("Request:", JSON.stringify(inquiryPayload, null, 2), "\n"); try { const inquiryRes = await fetch( `${SANDBOX_BASE}/cashpro/reporting/v1/transaction-inquiries/previous-day`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${accountInfoBearerToken}`, }, body: JSON.stringify(inquiryPayload), } ); const inquiryHeaders = Object.fromEntries(inquiryRes.headers.entries()); const inquiryText = await inquiryRes.text(); console.log("Status:", inquiryRes.status); console.log("Response Headers:", JSON.stringify(inquiryHeaders, null, 2)); console.log("Response Body:", inquiryText); } catch (err) { console.error("Transaction Inquiry request failed:", err.message); } console.log("\n" + "=".repeat(60)); console.log("Done. Look for: client ID, timestamp, transactionIdentification"); console.log("=".repeat(60)); } main().catch((err) => { console.error("Fatal error:", err); process.exit(1); });