Payment Retry Workflow

Processes subscription payments and queues failed payments to an SQS dead-letter queue for async retry. Sends a confirmation event to SQS on success.
{
  "Comment": "Payment retry workflow that queues failed payments to SQS for async retry processing",
  "StartAt": "ProcessPayment",
  "States": {
    "ProcessPayment": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "${ProcessPaymentFunctionArn}",
        "Payload.$": "$"
      },
      "ResultPath": "$.payment",
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 2,
          "BackoffRate": 2
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.error",
          "Next": "QueuePaymentRetry"
        }
      ],
      "Next": "DidPaymentSucceed"
    },
    "DidPaymentSucceed": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.payment.Payload.status",
          "StringEquals": "SUCCESS",
          "Next": "QueuePaymentConfirmation"
        },
        {
          "Variable": "$.payment.Payload.status",
          "StringEquals": "DECLINED",
          "Next": "QueuePaymentRetry"
        }
      ],
      "Default": "QueuePaymentRetry"
    },
    "QueuePaymentConfirmation": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sqs:sendMessage",
      "Parameters": {
        "QueueUrl": "https://sqs.us-east-1.amazonaws.com/123456789012/billing-confirmations",
        "MessageBody": {
          "event": "PAYMENT_SUCCEEDED",
          "subscriptionId.$": "$.subscriptionId",
          "tenantId.$": "$.tenantId",
          "amount.$": "$.payment.Payload.amount",
          "currency.$": "$.payment.Payload.currency",
          "transactionId.$": "$.payment.Payload.transactionId"
        }
      },
      "ResultPath": "$.confirmation",
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.confirmationError",
          "Next": "PaymentComplete"
        }
      ],
      "Next": "PaymentComplete"
    },
    "QueuePaymentRetry": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sqs:sendMessage",
      "Parameters": {
        "QueueUrl": "https://sqs.us-east-1.amazonaws.com/123456789012/payment-retry-dlq",
        "MessageBody": {
          "event": "PAYMENT_FAILED",
          "subscriptionId.$": "$.subscriptionId",
          "tenantId.$": "$.tenantId",
          "retryCount.$": "$.retryCount",
          "failureReason.$": "$.payment.Payload.declineReason"
        },
        "DelaySeconds": 60
      },
      "ResultPath": "$.retryEvent",
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 3,
          "BackoffRate": 1.5
        }
      ],
      "Next": "IsMaxRetriesExceeded"
    },
    "IsMaxRetriesExceeded": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.retryCount",
          "NumericGreaterThanEquals": 3,
          "Next": "MaxRetriesExceeded"
        }
      ],
      "Default": "PaymentFailed"
    },
    "MaxRetriesExceeded": {
      "Type": "Fail",
      "Error": "PaymentMaxRetriesExceeded",
      "Cause": "Payment failed after maximum retry attempts"
    },
    "PaymentFailed": {
      "Type": "Fail",
      "Error": "PaymentDeclined",
      "Cause": "Payment was declined and queued for retry"
    },
    "PaymentComplete": {
      "Type": "Succeed"
    }
  }
}
JSON
Expand
100%

SaaS 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.