Batch Payment Settlement

Processes an array of payments concurrently using a Map state. Each payment is independently validated, fraud-checked, authorized, and settled in parallel. Results are collected into a single batch summary with per-payment status records.

{
  "Comment": "Batch payment settlement — processes an array of payments concurrently using a Map state",
  "StartAt": "ProcessPaymentBatch",
  "States": {
    "ProcessPaymentBatch": {
      "Type": "Map",
      "ItemsPath": "$.payments",
      "ItemSelector": {
        "paymentId.$": "$$.Map.Item.Value.paymentId",
        "merchantId.$": "$$.Map.Item.Value.merchantId",
        "customerId.$": "$$.Map.Item.Value.customerId",
        "amount.$": "$$.Map.Item.Value.amount",
        "currency.$": "$$.Map.Item.Value.currency",
        "paymentMethod.$": "$$.Map.Item.Value.paymentMethod",
        "cardLastFour.$": "$$.Map.Item.Value.cardLastFour",
        "metadata.$": "$$.Map.Item.Value.metadata"
      },
      "MaxConcurrency": 3,
      "Iterator": {
        "StartAt": "ValidatePayment",
        "States": {
          "ValidatePayment": {
            "Type": "Task",
            "Resource": "arn:aws:states:::lambda:invoke",
            "Parameters": {
              "FunctionName": "${ValidatePaymentFunctionArn}",
              "Payload.$": "$"
            },
            "ResultPath": "$.validation",
            "Retry": [
              {
                "ErrorEquals": [
                  "Lambda.ServiceException",
                  "Lambda.AWSLambdaException",
                  "Lambda.SdkClientException"
                ],
                "IntervalSeconds": 2,
                "MaxAttempts": 3,
                "BackoffRate": 2
              }
            ],
            "Catch": [
              {
                "ErrorEquals": [
                  "States.ALL"
                ],
                "ResultPath": "$.error",
                "Next": "RecordValidationFailure"
              }
            ],
            "Next": "IsPaymentValid"
          },
          "IsPaymentValid": {
            "Type": "Choice",
            "Choices": [
              {
                "Variable": "$.validation.Payload.isValid",
                "BooleanEquals": true,
                "Next": "RunFraudCheck"
              }
            ],
            "Default": "RecordValidationFailure"
          },
          "RecordValidationFailure": {
            "Type": "Pass",
            "Parameters": {
              "paymentId.$": "$.paymentId",
              "status": "FAILED",
              "reason": "Validation failed"
            },
            "End": true
          },
          "RunFraudCheck": {
            "Type": "Task",
            "Resource": "arn:aws:states:::lambda:invoke",
            "Parameters": {
              "FunctionName": "${RunFraudCheckFunctionArn}",
              "Payload.$": "$.validation.Payload"
            },
            "ResultPath": "$.fraud",
            "Retry": [
              {
                "ErrorEquals": [
                  "States.ALL"
                ],
                "IntervalSeconds": 2,
                "MaxAttempts": 2,
                "BackoffRate": 2
              }
            ],
            "Catch": [
              {
                "ErrorEquals": [
                  "States.ALL"
                ],
                "ResultPath": "$.error",
                "Next": "RecordFraudCheckError"
              }
            ],
            "Next": "IsFraudulent"
          },
          "RecordFraudCheckError": {
            "Type": "Pass",
            "Parameters": {
              "paymentId.$": "$.paymentId",
              "status": "FAILED",
              "reason": "Fraud check service unavailable"
            },
            "End": true
          },
          "IsFraudulent": {
            "Type": "Choice",
            "Choices": [
              {
                "Variable": "$.fraud.Payload.isFraudulent",
                "BooleanEquals": true,
                "Next": "PublishFraudDetectedEvent"
              }
            ],
            "Default": "AuthorizePayment"
          },
          "PublishFraudDetectedEvent": {
            "Type": "Task",
            "Resource": "arn:aws:states:::events:putEvents",
            "Parameters": {
              "Entries": [
                {
                  "EventBusName": "default",
                  "Source": "thrubit.payments",
                  "DetailType": "PaymentFraudDetected",
                  "Detail": {
                    "paymentId.$": "$.fraud.Payload.paymentId",
                    "riskScore.$": "$.fraud.Payload.riskScore",
                    "riskLevel.$": "$.fraud.Payload.riskLevel",
                    "fraudSignals.$": "$.fraud.Payload.fraudSignals",
                    "amount.$": "$.validation.Payload.amount",
                    "currency.$": "$.validation.Payload.currency",
                    "merchantId.$": "$.validation.Payload.merchantId"
                  }
                }
              ]
            },
            "ResultPath": "$.fraudEventResult",
            "Next": "RecordFraudBlock"
          },
          "RecordFraudBlock": {
            "Type": "Pass",
            "Parameters": {
              "paymentId.$": "$.fraud.Payload.paymentId",
              "status": "BLOCKED",
              "reason": "Fraud detected",
              "riskScore.$": "$.fraud.Payload.riskScore"
            },
            "End": true
          },
          "AuthorizePayment": {
            "Type": "Task",
            "Resource": "arn:aws:states:::lambda:invoke",
            "Parameters": {
              "FunctionName": "${AuthorizePaymentFunctionArn}",
              "Payload.$": "$.validation.Payload"
            },
            "ResultPath": "$.authorization",
            "Retry": [
              {
                "ErrorEquals": [
                  "Lambda.ServiceException",
                  "Lambda.AWSLambdaException",
                  "Lambda.SdkClientException"
                ],
                "IntervalSeconds": 2,
                "MaxAttempts": 3,
                "BackoffRate": 2
              }
            ],
            "Catch": [
              {
                "ErrorEquals": [
                  "States.ALL"
                ],
                "ResultPath": "$.error",
                "Next": "RecordAuthorizationFailure"
              }
            ],
            "Next": "SettlePayment"
          },
          "RecordAuthorizationFailure": {
            "Type": "Pass",
            "Parameters": {
              "paymentId.$": "$.paymentId",
              "status": "FAILED",
              "reason": "Authorization declined"
            },
            "End": true
          },
          "SettlePayment": {
            "Type": "Task",
            "Resource": "arn:aws:states:::lambda:invoke",
            "Parameters": {
              "FunctionName": "${SettlePaymentFunctionArn}",
              "Payload.$": "$.authorization.Payload"
            },
            "ResultPath": "$.settlement",
            "Retry": [
              {
                "ErrorEquals": [
                  "Lambda.ServiceException",
                  "Lambda.AWSLambdaException",
                  "Lambda.SdkClientException"
                ],
                "IntervalSeconds": 3,
                "MaxAttempts": 3,
                "BackoffRate": 2
              }
            ],
            "Catch": [
              {
                "ErrorEquals": [
                  "States.ALL"
                ],
                "ResultPath": "$.error",
                "Next": "RecordSettlementFailure"
              }
            ],
            "Next": "PublishSettlementCompleteEvent"
          },
          "RecordSettlementFailure": {
            "Type": "Pass",
            "Parameters": {
              "paymentId.$": "$.paymentId",
              "status": "FAILED",
              "reason": "Settlement failed"
            },
            "End": true
          },
          "PublishSettlementCompleteEvent": {
            "Type": "Task",
            "Resource": "arn:aws:states:::events:putEvents",
            "Parameters": {
              "Entries": [
                {
                  "EventBusName": "default",
                  "Source": "thrubit.payments",
                  "DetailType": "PaymentSettled",
                  "Detail": {
                    "paymentId.$": "$.settlement.Payload.paymentId",
                    "settlementId.$": "$.settlement.Payload.settlementId",
                    "amount.$": "$.settlement.Payload.amount",
                    "currency.$": "$.settlement.Payload.currency",
                    "merchantId.$": "$.settlement.Payload.merchantId",
                    "settledAt.$": "$.settlement.Payload.settledAt"
                  }
                }
              ]
            },
            "ResultPath": "$.settlementEventResult",
            "Next": "RecordSuccess"
          },
          "RecordSuccess": {
            "Type": "Pass",
            "Parameters": {
              "paymentId.$": "$.settlement.Payload.paymentId",
              "settlementId.$": "$.settlement.Payload.settlementId",
              "status": "SETTLED",
              "amount.$": "$.settlement.Payload.amount",
              "currency.$": "$.settlement.Payload.currency"
            },
            "End": true
          }
        }
      },
      "ResultPath": "$.batchResults",
      "Next": "BatchComplete"
    },
    "BatchComplete": {
      "Type": "Succeed"
    }
  }
}
JSON
Expand
100%

Financial Services teams can use patterns like this to build reliable, compliant, and scalable automation for payment systems and can test and refine these flows locally with Thrubit to reduce cloud cost and speed up iteration.

Related Articles

  • business person working on a virtual aws state machine
  • thrubit industry financial bank