Subscription Cancellation

Handles subscription cancellation by queuing lifecycle and billing-stop events to SQS, with an optional waitForTaskToken async billing confirmation before final billing processing.
{
  "Comment": "SaaS subscription cancellation workflow with SQS event queuing",
  "StartAt": "ValidateCancellation",
  "States": {
    "ValidateCancellation": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "${CancelSubscriptionFunctionArn}",
        "Payload.$": "$"
      },
      "ResultPath": "$.cancellation",
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 3,
          "BackoffRate": 2
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.error",
          "Next": "CancellationFailed"
        }
      ],
      "Next": "IsCancellationEligible"
    },
    "IsCancellationEligible": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.cancellation.Payload.eligible",
          "BooleanEquals": true,
          "Next": "QueueCancellationEvent"
        }
      ],
      "Default": "CancellationFailed"
    },
    "CancellationFailed": {
      "Type": "Fail",
      "Error": "CancellationIneligible",
      "Cause": "Subscription is not eligible for cancellation"
    },
    "QueueCancellationEvent": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sqs:sendMessage",
      "Parameters": {
        "QueueUrl": "https://sqs.us-east-1.amazonaws.com/123456789012/subscription-lifecycle-events",
        "MessageBody": {
          "event": "SUBSCRIPTION_CANCELLATION_REQUESTED",
          "subscriptionId.$": "$.subscriptionId",
          "tenantId.$": "$.tenantId",
          "reason.$": "$.cancellationReason",
          "effectiveDate.$": "$.cancellation.Payload.effectiveDate"
        }
      },
      "ResultPath": "$.cancellationEvent",
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "IntervalSeconds": 2,
          "MaxAttempts": 3,
          "BackoffRate": 1.5
        }
      ],
      "Next": "QueueBillingStop"
    },
    "QueueBillingStop": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken",
      "Parameters": {
        "QueueUrl": "https://sqs.us-east-1.amazonaws.com/123456789012/subscription-lifecycle-events",
        "MessageBody": {
          "command": "STOP_BILLING",
          "subscriptionId.$": "$.subscriptionId",
          "tenantId.$": "$.tenantId",
          "taskToken.$": "$$.Task.Token"
        }
      },
      "ResultPath": "$.billingStop",
      "HeartbeatSeconds": 300,
      "Catch": [
        {
          "ErrorEquals": [
            "States.HeartbeatTimeout",
            "States.TaskFailed"
          ],
          "ResultPath": "$.billingError",
          "Next": "ProcessFinalBilling"
        }
      ],
      "Next": "ProcessFinalBilling"
    },
    "ProcessFinalBilling": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "${ProcessPaymentFunctionArn}",
        "Payload.$": "$"
      },
      "ResultPath": "$.finalBilling",
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "IntervalSeconds": 3,
          "MaxAttempts": 2,
          "BackoffRate": 2
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.error",
          "Next": "CancellationComplete"
        }
      ],
      "Next": "CancellationComplete"
    },
    "CancellationComplete": {
      "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.

Free Trial