Infrastructure
The Payments Service runs as 16 AWS Lambda functions backed by DynamoDB tables, SQS queues, and Kinesis streams. All infrastructure is managed via Terraform in deploy/.
Lambda Functions
All Lambdas share the same compiled binary distribution (dist/) and are deployed using the fmtf-module-lambda Terraform module. Timeouts marked with * are derived from an SQS queue’s visibility_timeout_seconds (worker = 90%, prenoter = 50%).
| Lambda | Trigger | Timeout | Memory | Max Concurrency |
|---|---|---|---|---|
|
API Gateway (IAM + JWT) |
300 s |
256 MB (512 MB in test) |
— |
|
SQS |
30 s* |
128 MB |
5 |
|
CloudWatch (15:30 UTC daily) |
900 s |
2048 MB |
— |
|
SQS |
54 s* |
128 MB |
5 |
|
CloudWatch (every 30 min, prod only) |
30 s |
128 MB |
— |
|
SQS |
540 s* |
1024 MB |
5 |
|
SQS |
540 s* |
128 MB |
5 |
|
DynamoDB Streams ( |
840 s |
128 MB |
— |
|
API Gateway ( |
300 s |
128 MB |
— |
|
SQS |
540 s* |
128 MB |
5 |
|
Kinesis |
840 s |
128 MB |
— |
|
CloudWatch (13:00 UTC daily + hourly, prod only) |
60 s |
128 MB |
— |
|
CloudWatch (13:00 UTC daily) |
600 s |
128 MB |
— |
|
CloudWatch (15:00 UTC daily) |
600 s |
128 MB |
1 |
|
SQS |
54 s* |
128 MB |
5 |
|
SQS |
30 s* |
128 MB |
5 |
kinesis-feeder and blocklist-handler are deployed in the legacy DynamoDB region (us-east-1). All other Lambdas run in the primary region (us-west-2 in test, us-east-2 in prod).
|
DynamoDB Tables
Full schema details (keys, GSIs, attribute types, access patterns) are in DynamoDB Tables.
| Table | Primary Key | Purpose |
|---|---|---|
|
|
Payment records — all payment types, statuses, and event tracking. |
|
|
Usio debit/credit tokens for pinless payments. |
|
|
KMS-encrypted bank account numbers and routing numbers. |
|
|
Usio refund transaction records. |
|
|
History of bank account changes per user. |
SQS Queues
Each queue has a corresponding DLQ. All DLQs have a 900-second visibility timeout.
| Queue | Producer | Consumer | Visibility Timeout | DLQ Receive Count |
|---|---|---|---|---|
|
Callers via API |
|
60 s |
10 |
|
|
|
600 s |
10 |
|
|
|
60 s |
1 |
|
Callers (bank account update events) |
|
600 s |
10 |
|
|
|
600 s |
10 |
|
|
|
60 s |
1 |
|
External callers |
|
60 s |
1 |
check-ach, usio-refresh, and debit-fixer queues use maxReceiveCount = 1, meaning a single processing failure sends the message directly to the DLQ without retry. For check-ach and usio-refresh this is intentional — each message represents a specific date/account batch and retrying could cause duplicate state updates. debit-fixer jobs are manually enqueued one-off repairs where retry semantics are the operator’s responsibility.
|
Kinesis Streams
| Stream | Producer | Consumers | Purpose |
|---|---|---|---|
|
|
|
Payment lifecycle events. The feeder reads the |
See Event Flows for the full list of published event types and payload structure.
CloudWatch Schedules
| Rule | Target Lambda | Schedule | Notes |
|---|---|---|---|
|
|
Every 30 min |
Prod only. Triggers Usio transaction sync for the past 35-minute window. |
|
|
15:30 UTC daily |
Polls JPM and Usio for |
|
|
15:00 UTC daily |
Refreshes expiring Usio debit/credit tokens. |
|
|
13:00 UTC daily |
Prod only. Posts merchant account balances to Slack. |
|
|
Every 1 hour |
Prod only. Posts condensed hourly balance update to Slack. |
|
|
13:00 UTC daily |
Syncs JPM transaction details to DynamoDB. |
Terraform Structure
All infrastructure lives in deploy/. The top-level files correspond to AWS resource groups:
| File | Contents |
|---|---|
|
All Lambda function modules (16 total). Also defines the API Gateway v2 (HTTP API). |
|
All SQS queues and their DLQs (7 queues + 7 DLQs). |
|
Kinesis stream data source reference ( |
|
EventBridge rules and targets for all scheduled Lambda triggers. |
|
REST API Gateway (v1) for legacy endpoints. The primary API uses API Gateway v2 (HTTP API) defined in |
|
KMS key reference for bank account encryption. |
|
Secrets Manager data source references (Usio, JPM, Plaid credentials, etc.). |
|
VPC, subnet, and security group data source references for API Gateway VPC link. |
|
|
|
|
|
Input variables: |
Deployment
v2 (Current)
The main branch is the current v2 default branch.
The code in the main branch is automatically deployed to the test environment in us-west-2 with the github workflow in .github/workflows/deploy.yaml.
We use release-please to keep a long running release PR of changes since the last release. Merging this PR will create a draft GitHub release that, once published, deploys to production in us-east-2.