diff --git a/.github/workflows/deploy-lambda.yml b/.github/workflows/deploy-lambda.yml
new file mode 100644
index 0000000..8a29a28
--- /dev/null
+++ b/.github/workflows/deploy-lambda.yml
@@ -0,0 +1,91 @@
+name: Deploy Thrive API to AWS Lambda
+
+on:
+ push:
+ branches:
+ - master
+ paths:
+ - 'API/ThriveChurchOfficialAPI/**'
+ - '.github/workflows/deploy-lambda.yml'
+ workflow_dispatch:
+
+env:
+ AWS_REGION: us-east-2
+ STACK_NAME: thrive-api-lambda
+
+permissions:
+ id-token: write
+ contents: read
+ actions: read
+
+jobs:
+ deploy:
+ name: Build and Deploy Lambda
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup .NET 8.0
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '8.0.x'
+
+ - name: Setup SAM CLI
+ uses: aws-actions/setup-sam@v2
+
+ - name: Configure AWS credentials
+ uses: aws-actions/configure-aws-credentials@v4
+ with:
+ role-to-assume: arn:aws:iam::349570132161:role/GitHub_OIDC
+ aws-region: ${{ env.AWS_REGION }}
+
+ - name: Build SAM application
+ working-directory: ./API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI
+ run: sam build --template-file serverless.template
+
+ - name: Deploy SAM application
+ working-directory: ./API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI
+ run: |
+ sam deploy \
+ --stack-name ${{ env.STACK_NAME }} \
+ --region ${{ env.AWS_REGION }} \
+ --s3-bucket thrive-sam-deployments \
+ --no-confirm-changeset \
+ --no-fail-on-empty-changeset \
+ --capabilities CAPABILITY_IAM
+
+ - name: Get API Gateway URL
+ id: get-url
+ run: |
+ API_URL=$(aws cloudformation describe-stacks \
+ --stack-name ${{ env.STACK_NAME }} \
+ --query "Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue" \
+ --output text \
+ --region ${{ env.AWS_REGION }})
+ echo "api-url=$API_URL" >> $GITHUB_OUTPUT
+ echo "API Gateway URL: $API_URL"
+
+ - name: Test Lambda deployment
+ run: |
+ API_URL="${{ steps.get-url.outputs.api-url }}"
+
+ echo "Testing Lambda deployment at: ${API_URL}api/health/live"
+ sleep 10
+
+ HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${API_URL}api/health/live")
+
+ if [ "$HTTP_STATUS" -eq 200 ]; then
+ echo "Lambda deployment successful! Health check returned 200"
+ else
+ echo "Lambda deployment may have issues. Health check returned: $HTTP_STATUS"
+ exit 1
+ fi
+
+ - name: Deployment summary
+ run: |
+ echo "Deployment Complete!"
+ echo "Stack Name: ${{ env.STACK_NAME }}"
+ echo "Region: ${{ env.AWS_REGION }}"
+ echo "API Gateway URL: ${{ steps.get-url.outputs.api-url }}"
diff --git a/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/LambdaEntryPoint.cs b/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/LambdaEntryPoint.cs
new file mode 100644
index 0000000..a9f59dc
--- /dev/null
+++ b/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/LambdaEntryPoint.cs
@@ -0,0 +1,45 @@
+/*
+ MIT License
+
+ Copyright (c) 2026 Thrive Community Church
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using Amazon.Lambda.AspNetCoreServer;
+using Microsoft.AspNetCore.Hosting;
+
+namespace ThriveChurchOfficialAPI
+{
+ ///
+ /// Lambda entry point that wraps the ASP.NET Core application.
+ /// This allows the same controllers, services, and repositories to run in AWS Lambda.
+ ///
+ public class LambdaEntryPoint : APIGatewayProxyFunction
+ {
+ ///
+ /// Initialize the Lambda function with the ASP.NET Core Startup class.
+ ///
+ protected override void Init(IWebHostBuilder builder)
+ {
+ builder.UseStartup();
+ }
+ }
+}
+
diff --git a/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI.csproj b/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI.csproj
index d1d6e65..5c25f16 100644
--- a/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI.csproj
+++ b/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI.csproj
@@ -21,6 +21,9 @@
+
+
+
diff --git a/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/aws-lambda-tools-defaults.json b/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/aws-lambda-tools-defaults.json
new file mode 100644
index 0000000..12ed7a9
--- /dev/null
+++ b/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/aws-lambda-tools-defaults.json
@@ -0,0 +1,21 @@
+{
+ "Information": [
+ "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
+ "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
+ "dotnet lambda help",
+ "All the command line options for the Lambda command can be specified in this file."
+ ],
+ "profile": "default",
+ "region": "us-east-2",
+ "configuration": "Release",
+ "function-runtime": "dotnet8",
+ "function-memory-size": 512,
+ "function-timeout": 30,
+ "function-handler": "ThriveChurchOfficialAPI::ThriveChurchOfficialAPI.LambdaEntryPoint::FunctionHandlerAsync",
+ "framework": "net8.0",
+ "s3-bucket": "",
+ "s3-prefix": "ThriveChurchOfficialAPI/",
+ "template": "serverless.template",
+ "template-parameters": ""
+}
+
diff --git a/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/serverless.template b/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/serverless.template
new file mode 100644
index 0000000..1358d9b
--- /dev/null
+++ b/API/ThriveChurchOfficialAPI/ThriveChurchOfficialAPI/serverless.template
@@ -0,0 +1,173 @@
+{
+ "AWSTemplateFormatVersion": "2010-09-09",
+ "Transform": "AWS::Serverless-2016-10-31",
+ "Description": "Thrive Church Official API - Lambda Deployment",
+ "Resources": {
+ "ThriveApiFunction": {
+ "Type": "AWS::Serverless::Function",
+ "Properties": {
+ "Handler": "ThriveChurchOfficialAPI::ThriveChurchOfficialAPI.LambdaEntryPoint::FunctionHandlerAsync",
+ "Runtime": "dotnet8",
+ "CodeUri": "",
+ "MemorySize": 1024,
+ "Timeout": 30,
+ "Role": "arn:aws:iam::349570132161:role/ThriveApiAppRunnerRole",
+ "ReservedConcurrentExecutions": 10,
+ "Environment": {
+ "Variables": {
+ "ASPNETCORE_ENVIRONMENT": "Production",
+ "PORT": "8080",
+ "MongoConnectionString": "{{resolve:secretsmanager:thrive-api/database-hzetzL:SecretString:MongoConnectionString}}",
+ "TokenConnectionStringPath": "Hashables",
+ "EsvApiKey": "{{resolve:secretsmanager:thrive/3rd-party-eohiNX:SecretString:EsvApiKey}}",
+ "OverrideEsvApiKey": "false",
+ "EmailPW": "{{resolve:secretsmanager:thrive-api/auth-zrM22S:SecretString:EmailPassword}}",
+ "S3__BucketName": "thrive-audio",
+ "S3__AccessKey": "{{resolve:secretsmanager:thrive-api/s3-U1eiYO:SecretString:AccessKey}}",
+ "S3__SecretKey": "{{resolve:secretsmanager:thrive-api/s3-U1eiYO:SecretString:SecretKey}}",
+ "S3__Region": "us-east-2",
+ "S3__BaseUrl": "https://podcast.thrive-fl.org",
+ "S3__MaxFileSizeMB": "50",
+ "JWT__SecretKey": "{{resolve:secretsmanager:thrive-api/auth-zrM22S:SecretString:JwtSecretKey}}",
+ "JWT__Issuer": "ThriveChurchOfficialAPI",
+ "JWT__Audience": "ThriveChurchClients",
+ "JWT__ExpirationMinutes": "60",
+ "JWT__RefreshTokenExpirationDays": "7",
+ "RedisConnectionString": "{{resolve:secretsmanager:thrive-api/database-hzetzL:SecretString:RedisConnectionString}}",
+ "IpRateLimiting__EnableEndpointRateLimiting": "false",
+ "IpRateLimiting__StackBlockedRequests": "true",
+ "IpRateLimiting__HttpStatusCode": "429"
+ }
+ },
+ "Events": {
+ "ProxyResource": {
+ "Type": "HttpApi",
+ "Properties": {
+ "Path": "/{proxy+}",
+ "Method": "ANY"
+ }
+ },
+ "RootResource": {
+ "Type": "HttpApi",
+ "Properties": {
+ "Path": "/",
+ "Method": "ANY"
+ }
+ }
+ }
+ }
+ },
+ "AlarmNotificationTopic": {
+ "Type": "AWS::SNS::Topic",
+ "Properties": {
+ "TopicName": "ThriveAPI-Alarms",
+ "DisplayName": "Thrive API Health Alerts",
+ "Subscription": [
+ {
+ "Endpoint": "wyatt@thrive-fl.org",
+ "Protocol": "email"
+ }
+ ]
+ }
+ },
+ "LambdaErrorAlarm": {
+ "Type": "AWS::CloudWatch::Alarm",
+ "Properties": {
+ "AlarmName": "ThriveAPI-Lambda-Errors",
+ "AlarmDescription": "Alert when Lambda function has errors",
+ "MetricName": "Errors",
+ "Namespace": "AWS/Lambda",
+ "Statistic": "Sum",
+ "Period": 300,
+ "EvaluationPeriods": 1,
+ "Threshold": 5,
+ "ComparisonOperator": "GreaterThanThreshold",
+ "Dimensions": [
+ {
+ "Name": "FunctionName",
+ "Value": {
+ "Ref": "ThriveApiFunction"
+ }
+ }
+ ],
+ "TreatMissingData": "notBreaching",
+ "AlarmActions": [
+ {
+ "Ref": "AlarmNotificationTopic"
+ }
+ ]
+ }
+ },
+ "LambdaThrottleAlarm": {
+ "Type": "AWS::CloudWatch::Alarm",
+ "Properties": {
+ "AlarmName": "ThriveAPI-Lambda-Throttles",
+ "AlarmDescription": "Alert when Lambda function is throttled",
+ "MetricName": "Throttles",
+ "Namespace": "AWS/Lambda",
+ "Statistic": "Sum",
+ "Period": 300,
+ "EvaluationPeriods": 1,
+ "Threshold": 1,
+ "ComparisonOperator": "GreaterThanThreshold",
+ "Dimensions": [
+ {
+ "Name": "FunctionName",
+ "Value": {
+ "Ref": "ThriveApiFunction"
+ }
+ }
+ ],
+ "TreatMissingData": "notBreaching",
+ "AlarmActions": [
+ {
+ "Ref": "AlarmNotificationTopic"
+ }
+ ]
+ }
+ },
+ "ApiGateway5xxAlarm": {
+ "Type": "AWS::CloudWatch::Alarm",
+ "Properties": {
+ "AlarmName": "ThriveAPI-Gateway-5xx-Errors",
+ "AlarmDescription": "Alert when API Gateway returns 5xx errors",
+ "MetricName": "5XXError",
+ "Namespace": "AWS/ApiGateway",
+ "Statistic": "Sum",
+ "Period": 300,
+ "EvaluationPeriods": 1,
+ "Threshold": 5,
+ "ComparisonOperator": "GreaterThanThreshold",
+ "Dimensions": [
+ {
+ "Name": "ApiId",
+ "Value": {
+ "Ref": "ServerlessHttpApi"
+ }
+ }
+ ],
+ "TreatMissingData": "notBreaching",
+ "AlarmActions": [
+ {
+ "Ref": "AlarmNotificationTopic"
+ }
+ ]
+ }
+ }
+ },
+ "Outputs": {
+ "ApiUrl": {
+ "Description": "API Gateway endpoint URL",
+ "Value": {
+ "Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/"
+ }
+ },
+ "LambdaFunctionName": {
+ "Description": "Lambda function name",
+ "Value": {
+ "Ref": "ThriveApiFunction"
+ }
+ }
+ }
+}
+