FIFO Payments Ledger
AWS architecture template · Exactly-once payment processing with FIFO SQS deduplication, conditional DynamoDB writes for idempotency, CMK encryption, and a DLQ alert path.
FIFO Payments Ledger is a free AWS architecture template built with Lambda, SQS, API Gateway, CloudWatch, DynamoDB, IAM, KMS, Secrets Manager and SNS. Open it in TheArchitect to edit the diagram, estimate monthly cost, and export the CloudFormation or Terraform that deploys it.
AWS services in this template
- Lambda×2
- SQS×2
- API Gateway
- CloudWatch
- DynamoDB
- IAM
- KMS
- Secrets Manager
- SNS
Deployment notes
Needs input
- Store PSP API credentials in Secrets Manager before deploying.
- Set SQS FIFO queue URL as Lambda event source mapping.
- KMS CMK must be created and key ARN referenced in DynamoDB SSE config.
Generated CloudFormation — 13 resources
| Logical ID | Resource type |
|---|---|
| PaymentsAPIapigateway | AWS::ApiGateway::RestApi |
| PaymentIntakelambda | AWS::Lambda::Function |
| LedgerQueueFIFOsqs | AWS::SQS::Queue |
| LedgerWriterlambda | AWS::Lambda::Function |
| LedgerTabledynamodb | AWS::DynamoDB::Table |
| LedgerCMKkms | AWS::KMS::Key |
| PSPCredentialssecretsmanager | AWS::SecretsManager::Secret |
| DLQFIFOsqs | AWS::SQS::Queue |
| DLQAlarmcloudwatch | AWS::CloudWatch::Alarm |
| PagerAlertssns | AWS::SNS::Topic |
| WriterRoleiam | AWS::IAM::Role |
| PaymentIntakelambdaLedgerQueueFIFOsqsEventSourceMapping | AWS::Lambda::EventSourceMapping |
| LedgerWriterlambdaLedgerQueueFIFOsqsEventSourceMapping | AWS::Lambda::EventSourceMapping |
View the full CloudFormation template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Generated by TheArchitect — https://www.thecloudarchitect.dev",
"Metadata": {
"TheArchitect": {
"Edges": [
{
"From": "PaymentIntakelambda",
"To": "LedgerQueueFIFOsqs",
"Label": "enqueue ordered"
},
{
"From": "LedgerQueueFIFOsqs",
"To": "LedgerWriterlambda",
"Label": "BatchSize=1"
},
{
"From": "LedgerWriterlambda",
"To": "LedgerTabledynamodb",
"Label": "conditional PutItem"
},
{
"From": "DLQAlarmcloudwatch",
"To": "PagerAlertssns",
"Label": "alarm action"
},
{
"From": "WriterRoleiam",
"To": "LedgerWriterlambda",
"Label": "execution role"
}
]
}
},
"Resources": {
"PaymentsAPIapigateway": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "payments-api",
"Description": "Payments Intake REST API",
"EndpointConfiguration": {
"Types": [
"REGIONAL"
]
}
}
},
"PaymentIntakelambda": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "payment-intake",
"Runtime": "nodejs20.x",
"Handler": "intake.handler",
"MemorySize": 256,
"Timeout": 10,
"Description": "Validates payment request and enqueues to FIFO queue with MessageGroupId=merchant_id and client-generated MessageDeduplicationId."
}
},
"LedgerQueueFIFOsqs": {
"Type": "AWS::SQS::Queue",
"Properties": {
"QueueName": "ledger-queue.fifo",
"VisibilityTimeout": 120,
"MessageRetentionPeriod": 86400,
"ReceiveMessageWaitTimeSeconds": 20
}
},
"LedgerWriterlambda": {
"Type": "AWS::Lambda::Function",
"DependsOn": [
"WriterRoleiam"
],
"Properties": {
"FunctionName": "ledger-writer",
"Runtime": "nodejs20.x",
"Handler": "writer.handler",
"MemorySize": 512,
"Timeout": 60,
"Description": "Processes one message at a time (BatchSize=1). Performs conditional PutItem on DynamoDB using transaction_id as idempotency key. Fetches PSP key from Secrets Manager.",
"Role": {
"Fn::GetAtt": [
"WriterRoleiam",
"Arn"
]
}
}
},
"LedgerTabledynamodb": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"TableName": "ledger",
"BillingMode": "PAY_PER_REQUEST",
"AttributeDefinitions": [
{
"AttributeName": "id",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "id",
"KeyType": "HASH"
}
],
"PointInTimeRecoverySpecification": {
"PointInTimeRecoveryEnabled": true
}
}
},
"LedgerCMKkms": {
"Type": "AWS::KMS::Key",
"Properties": {
"Description": "Ledger CMK — encrypts DynamoDB and Secrets Manager",
"EnableKeyRotation": true,
"Enabled": true,
"PendingWindowInDays": 30
}
},
"PSPCredentialssecretsmanager": {
"Type": "AWS::SecretsManager::Secret",
"Properties": {
"Name": "payments/psp-credentials",
"Description": "PSP API key and webhook secret for payment processor integration",
"GenerateSecretString": {
"PasswordLength": 32
}
}
},
"DLQFIFOsqs": {
"Type": "AWS::SQS::Queue",
"Properties": {
"QueueName": "ledger-dlq.fifo",
"MessageRetentionPeriod": 1209600
}
},
"DLQAlarmcloudwatch": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName": "ledger-dlq-not-empty",
"AlarmDescription": "Payment message reached DLQ — investigate ledger writer errors immediately",
"Namespace": "AWS/SQS",
"MetricName": "ApproximateNumberOfMessagesVisible",
"Statistic": "Sum",
"Period": 60,
"EvaluationPeriods": 1,
"Threshold": 1,
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"TreatMissingData": "notBreaching"
}
},
"PagerAlertssns": {
"Type": "AWS::SNS::Topic",
"Properties": {
"TopicName": "payments-pager-alerts",
"DisplayName": "Payments Pager Alerts"
}
},
"WriterRoleiam": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "ledger-writer-role",
"Description": "Lambda execution role for ledger writer — SQS + DynamoDB + Secrets Manager + KMS",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
"arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole"
]
}
},
"PaymentIntakelambdaLedgerQueueFIFOsqsEventSourceMapping": {
"Type": "AWS::Lambda::EventSourceMapping",
"DependsOn": [
"PaymentIntakelambda",
"LedgerQueueFIFOsqs"
],
"Properties": {
"EventSourceArn": {
"Fn::GetAtt": [
"LedgerQueueFIFOsqs",
"Arn"
]
},
"FunctionName": {
"Ref": "PaymentIntakelambda"
},
"Enabled": true,
"BatchSize": 10
}
},
"LedgerWriterlambdaLedgerQueueFIFOsqsEventSourceMapping": {
"Type": "AWS::Lambda::EventSourceMapping",
"DependsOn": [
"LedgerWriterlambda",
"LedgerQueueFIFOsqs"
],
"Properties": {
"EventSourceArn": {
"Fn::GetAtt": [
"LedgerQueueFIFOsqs",
"Arn"
]
},
"FunctionName": {
"Ref": "LedgerWriterlambda"
},
"Enabled": true,
"BatchSize": 10
}
}
}
}Generated by TheArchitect from the diagram above. Review values such as names, CIDR ranges and instance sizes before deploying to your account.