Bumps [fast-xml-builder](https://github.com/NaturalIntelligence/fast-xml-builder) from 1.1.5 to 1.2.0. - [Changelog](https://github.com/NaturalIntelligence/fast-xml-builder/blob/main/CHANGELOG.md) - [Commits](https://github.com/NaturalIntelligence/fast-xml-builder/compare/v1.1.5...v1.2.0) --- updated-dependencies: - dependency-name: fast-xml-builder dependency-version: 1.2.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|---|---|---|
| .claude | ||
| .github | ||
| scripts | ||
| src | ||
| .gitignore | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| template.yaml | ||
Payments Dashboard
AWS SAM application that ingests payment CSVs, syncs check data with Bank of America CashPro APIs, processes Gusto payroll confirmation emails into Slack notifications, and surfaces an outstanding-payments dashboard in Slack.
Architecture
- ProcessPayrollEmail — Lambda triggered by S3 (inbound email) and SQS (batch timer). SES receives Gusto payroll emails at
payroll@int.seahaven.com, stores them to S3, and this Lambda parses the email body, extracts financial data, and posts a combined Slack notification (employee payroll + contractor payments) after a 10-minute batching window. Runs outside VPC. - ProcessPaymentCsv — Lambda triggered by S3 CSV upload. Parses Stampli payment exports, upserts to DynamoDB, and submits new/cancelled checks to the CashPro Check Management API.
- FetchBoaTransactions — Scheduled Lambda (weekdays 9am ET). Calls the CashPro Previous Day Transaction Inquiry API and matches cleared/returned checks back to DynamoDB records.
- SlackAppHome — Lambda behind API Gateway. Renders the payments dashboard on the Slack App Home tab with outstanding aging buckets and drill-down modals.
ProcessPaymentCsv, FetchBoaTransactions, and SlackAppHome run inside a VPC with a NAT Gateway for a static outbound IP (required by BoA IP whitelisting). ProcessPayrollEmail runs outside the VPC.
Payroll Email Pipeline
Gusto sends payroll confirmation emails when payroll is run. A Gmail filter on adam@seahavenind.com auto-forwards emails from automated@gusto.com and gustonoreply@gusto.com to payroll@int.seahaven.com.
Flow: Gmail forward → SES receipt rule → S3 bucket → Lambda parses email → DynamoDB (pending) → SQS delay queue (10 min) → Lambda batches all pending items for that date → single Slack message → DynamoDB (notified)
Deduplication: Each email is deduplicated by DynamoDB key (PAYROLL_EMAIL#employee#<date> or PAYROLL_EMAIL#contractor#<date>#<bank-suffix>). The batch post is deduplicated by PAYROLL_BATCH#<date>. All items have a 90-day TTL.
BoA CashPro API Integration
Two separate CashPro APIs are used, each with its own OAuth credentials:
| API | Purpose | Endpoint |
|---|---|---|
| Check Management | Issue and cancel checks | /cashpro/checkmanagement/v1/check-issues |
| Reporting (Transaction Inquiry) | Fetch previous-day transactions | /cashpro/reporting/v1/transaction-inquiries/previous-day |
Authentication flow:
- POST to
/authn/v1/client-authenticationwithapplicationID,client_id, andclient_secret - Receive a Bearer
access_token(valid 1 hour) - Pass the token in the
Authorizationheader for subsequent API calls
Base URLs:
- Production:
https://api.bofa.com - Sandbox:
https://api-sb.bofa.com
SSM Parameters
All BoA credentials and config are stored in AWS SSM Parameter Store (SecureString):
| Parameter | Description |
|---|---|
/payments-dashboard/boa-check-mgmt-app-id |
Check Management application ID |
/payments-dashboard/boa-check-mgmt-client-id |
Check Management client ID |
/payments-dashboard/boa-check-mgmt-token |
Check Management client secret |
/payments-dashboard/boa-reporting-app-id |
Reporting application ID |
/payments-dashboard/boa-account-info-client-id |
Reporting client ID |
/payments-dashboard/boa-account-info-token |
Reporting client secret |
/payments-dashboard/boa-account-number |
BoA account number |
/payments-dashboard/boa-company-id |
CashPro company ID (check management) |
/payments-dashboard/boa-bank-id |
BoA routing number |
/payments-dashboard/slack-bot-token |
Slack Bot OAuth token |
Scripts
| Script | Purpose |
|---|---|
scripts/test-boa-sandbox.js |
One-off sandbox connectivity test for both CashPro APIs |
scripts/seed-from-csv.js |
Seed DynamoDB from a local CSV file |
scripts/seed-bank-status.js |
Seed bank clear status data into DynamoDB |
Deployment
sam build
sam deploy --guided
The BOA_BASE_URL environment variable in template.yaml controls whether Lambdas hit production (https://api.bofa.com) or sandbox (https://api-sb.bofa.com). All other BoA config is read from SSM at runtime.