Credit Card Transaction Processing

This workflow models a complete end to end credit card transaction pipeline using AWS Step Functions. It includes input validation, data enrichment, fraud analysis, balance checks, fund reservation, and final ledger posting.

{
  "Comment": "Credit card transaction processing workflow",
  "StartAt": "ValidateInput",
  "States": {
    "ValidateInput": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:REGION:ACCOUNT_ID:function:validate-transaction",
        "Payload.$": "$"
      },
      "ResultPath": "$.validation",
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 3,
          "BackoffRate": 2.0
        }
      ],
      "Catch": [
        {
          "ErrorEquals": ["States.ALL"],
          "ResultPath": "$.error",
          "Next": "ValidationError"
        }
      ],
      "Next": "IsValid"
    },
    "IsValid": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.validation.Payload.isValid",
          "BooleanEquals": true,
          "Next": "EnrichTransaction"
        }
      ],
      "Default": "ValidationError"
    },
    "ValidationError": {
      "Type": "Fail",
      "Error": "InvalidTransaction",
      "Cause": "Incoming transaction failed validation"
    },
    "EnrichTransaction": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:REGION:ACCOUNT_ID:function:enrich-transaction",
        "Payload.$": "$"
      },
      "ResultPath": "$.enriched",
      "Retry": [
        {
          "ErrorEquals": ["States.ALL"],
          "IntervalSeconds": 2,
          "MaxAttempts": 2,
          "BackoffRate": 2.0
        }
      ],
      "Catch": [
        {
          "ErrorEquals": ["States.ALL"],
          "ResultPath": "$.error",
          "Next": "EnrichmentError"
        }
      ],
      "Next": "FraudCheck"
    },
    "EnrichmentError": {
      "Type": "Fail",
      "Error": "EnrichmentFailed",
      "Cause": "Could not enrich transaction data"
    },
    "FraudCheck": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:REGION:ACCOUNT_ID:function:fraud-check",
        "Payload.$": "$.enriched.Payload"
      },
      "ResultPath": "$.fraud",
      "TimeoutSeconds": 10,
      "Catch": [
        {
          "ErrorEquals": ["States.ALL"],
          "ResultPath": "$.error",
          "Next": "FraudError"
        }
      ],
      "Next": "IsNotFraudulent"
    },
    "FraudError": {
      "Type": "Fail",
      "Error": "FraudCheckFailed",
      "Cause": "Fraud engine failure"
    },
    "IsNotFraudulent": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.fraud.Payload.isFraudulent",
          "BooleanEquals": false,
          "Next": "BalanceCheck"
        }
      ],
      "Default": "RejectTransactionFraud"
    },
    "RejectTransactionFraud": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:REGION:ACCOUNT_ID:function:reject-transaction",
        "Payload": {
          "reason": "FRAUD_SUSPECTED",
          "transaction.$": "$"
        }
      },
      "ResultPath": "$.rejection",
      "End": true
    },
    "BalanceCheck": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:REGION:ACCOUNT_ID:function:balance-check",
        "Payload": {
          "accountId.$": "$.enriched.Payload.accountId",
          "amount.$": "$.enriched.Payload.amount",
          "currency.$": "$.enriched.Payload.currency"
        }
      },
      "ResultPath": "$.balance",
      "Catch": [
        {
          "ErrorEquals": ["States.ALL"],
          "ResultPath": "$.error",
          "Next": "BalanceError"
        }
      ],
      "Next": "HasSufficientFunds"
    },
    "BalanceError": {
      "Type": "Fail",
      "Error": "BalanceCheckFailed",
      "Cause": "Unable to check account balance"
    },
    "HasSufficientFunds": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.balance.Payload.hasSufficientFunds",
          "BooleanEquals": true,
          "Next": "ReserveFunds"
        }
      ],
      "Default": "RejectTransactionInsufficientFunds"
    },
    "RejectTransactionInsufficientFunds": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:REGION:ACCOUNT_ID:function:reject-transaction",
        "Payload": {
          "reason": "INSUFFICIENT_FUNDS",
          "transaction.$": "$"
        }
      },
      "ResultPath": "$.rejection",
      "End": true
    },
    "ReserveFunds": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:REGION:ACCOUNT_ID:function:reserve-funds",
        "Payload": {
          "accountId.$": "$.enriched.Payload.accountId",
          "amount.$": "$.enriched.Payload.amount",
          "currency.$": "$.enriched.Payload.currency",
          "transactionId.$": "$.enriched.Payload.transactionId"
        }
      },
      "ResultPath": "$.reservation",
      "Catch": [
        {
          "ErrorEquals": ["States.ALL"],
          "ResultPath": "$.error",
          "Next": "ReservationError"
        }
      ],
      "Next": "PostTransaction"
    },
    "ReservationError": {
      "Type": "Fail",
      "Error": "ReservationFailed",
      "Cause": "Unable to reserve funds for transaction"
    },
    "PostTransaction": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:REGION:ACCOUNT_ID:function:post-transaction",
        "Payload": {
          "transaction.$": "$.enriched.Payload",
          "reservation.$": "$.reservation.Payload"
        }
      },
      "ResultPath": "$.posting",
      "Catch": [
        {
          "ErrorEquals": ["States.ALL"],
          "ResultPath": "$.error",
          "Next": "PostingError"
        }
      ],
      "Next": "Success"
    },
    "PostingError": {
      "Type": "Fail",
      "Error": "PostingFailed",
      "Cause": "Failed to post transaction to ledger"
    },
    "Success": {
      "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.

Workflow Explanation

Simulates a full credit card transaction life cycle

This workflow represents the complete journey of a card transaction from the moment it enters the system to the moment it is approved or rejected. It includes every stage a financial institution must perform, such as request validation, data enrichment, fraud analysis, balance verification, fund reservation, and final ledger posting. The result is a realistic model of a production grade financial pipeline that mirrors how real payment systems operate.

Includes failure handling across all major checkpoints

Financial operations demand high reliability, so the workflow incorporates robust error handling at every step. Each task includes retry logic to guard against temporary service interruptions, along with clearly defined catch states that route hard failures to predictable outcomes. This structure helps teams trace issues accurately, maintain data integrity, and ensure stable behavior in high pressure environments.

Ideal for financial services teams building regulated automation

Banks, credit card issuers, and payment processors must operate under strict audit and compliance requirements. This workflow follows patterns that support those needs. Each decision is explicit, each error path is deterministic, and every transformation occurs in an isolated state. This makes the workflow easier for compliance teams to review and supports clear documentation for internal audits.

Easy to test offline using Thrubit

Because the workflow is built entirely with Step Functions primitives and Lambda tasks, it can be executed locally using Thrubit without relying on cloud deployments. Developers can test a wide range of scenarios, simulate failure conditions, and verify orchestration behavior without incurring AWS costs. This significantly accelerates iteration speed and results in fewer surprises during production rollout.

Supports extension with Map states for batch payment processing

Many financial workflows run in batches, such as nightly settlements or check clearing windows. This workflow can be expanded with Map or Distributed Map states to process large volumes of transactions in parallel. This allows teams to build patterns similar to high scale financial systems, including the type of distributed processing highlighted in the Capital One check clearing example.

Works as a foundation for other financial workflows

Although this workflow focuses on credit card payments, the same structure can support ACH transfers, mobile check deposits, loan processing, internal settlement workflows, and fraud detection pipelines. By separating validation, enrichment, risk analysis, balance checking, and posting, it becomes a flexible template for any operation that moves money or relies on compliant financial decision flows.

Related Articles

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