Internal payments tracking dashboard
Find a file
dependabot[bot] 24e49b2a8b
Bump @aws-sdk/client-sqs from 3.1039.0 to 3.1041.0
Bumps [@aws-sdk/client-sqs](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-sqs) from 3.1039.0 to 3.1041.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-sqs/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.1041.0/clients/client-sqs)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-sqs"
  dependency-version: 3.1041.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-02 21:17:30 +00:00
.claude Add .claude configuration directory 2026-04-27 19:14:54 -04:00
.github Add Dependabot version update configuration 2026-05-02 17:14:26 -04:00
scripts Log BoA submissions to DDB and surface in Slack App Home 2026-04-20 17:40:55 -04:00
src Fix Lambda compliance and rename SQS queue 2026-04-30 14:15:05 -04:00
.gitignore Log BoA submissions to DDB and surface in Slack App Home 2026-04-20 17:40:55 -04:00
package-lock.json Bump @aws-sdk/client-sqs from 3.1039.0 to 3.1041.0 2026-05-02 21:17:30 +00:00
package.json Bump @aws-sdk/client-sqs from 3.1039.0 to 3.1041.0 2026-05-02 21:17:30 +00:00
README.md Update README with payroll email pipeline documentation 2026-04-30 14:19:06 -04:00
template.yaml Fix Lambda compliance and rename SQS queue 2026-04-30 14:15:05 -04:00

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:

  1. POST to /authn/v1/client-authentication with applicationID, client_id, and client_secret
  2. Receive a Bearer access_token (valid 1 hour)
  3. Pass the token in the Authorization header 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.