Lambda Functions
This page details the five Lambda functions that make up the Underwriting Service, including their configurations, environment variables, IAM permissions, and operational characteristics.
Overview
The Underwriting Service consists of five Lambda functions that work together in an event-driven architecture:
| Lambda | Trigger | Purpose | Concurrency |
|---|---|---|---|
API |
API Gateway |
REST API for eligibility checks and profile management |
High (synchronous) |
Rule Runner |
SQS |
Executes individual rule evaluations |
Medium (async batch) |
Result Runner |
SQS |
Aggregates rule outcomes into final decisions |
Medium (async batch) |
Float Created Handler |
SQS (EventBridge) |
Creates permanent evaluation records |
Low (event-driven) |
Profile Handler |
SQS (EventBridge) |
Creates default profiles for new users |
Low (event-driven) |
Request Flow
The following diagram shows how requests flow through the Lambda functions:
Three Processing Paths:
-
Synchronous (Cache Hit): API Lambda returns cached EvaluationResult immediately (HTTP 200)
-
Asynchronous (Cache Miss): Returns HTTP 200, triggers Rule Runner and Result Runner via SQS, client polls for results
-
Instant (Synchronous):
POST /instantinvokes Rule Runner and Result Runner Lambdas directly (RequestResponse), returns a fresh result without polling
Common Configuration
All Lambdas Share:
-
Memory Size: 512 MB (configurable via
local.lambda_memory_size) -
Runtime: Go 1.20+
-
VPC: Deployed in private subnets (API and Rule Runner only)
-
Monitoring: Datadog integration enabled
-
Logging: CloudWatch Logs with structured logging (golflog)
API Lambda
Entry Point: [cmd/api/main.go](cmd/api/main.go)
Purpose
Serves as the REST API gateway for the Underwriting Service. Handles all synchronous requests for float/loan eligibility checks, profile management, and evaluation history retrieval.
Key Responsibilities
-
Authentication & Authorization:
-
Validates AWS SigV4 signatures
-
Extracts user context from authorizer
-
-
Float/Loan Eligibility Checks:
-
Routes:
GET /{user_id}/float_check,/{user_id}/underwriting/eligibility,/{user_id}/underwriting/loan/check -
Retrieves cached evaluations from DynamoDB
-
Applies bypass logic for data quality issues
-
Returns approval status with amounts and reasons
-
-
Instant Synchronous Evaluation:
-
Route:
POST /{user_id}/underwriting/instant -
Invokes Rule Runner and Result Runner Lambdas synchronously (RequestResponse mode)
-
Returns a fresh evaluation result in a single request without async polling
-
Intended for signup and reactivation flows where data is known to be available
-
-
Float Profile Management:
-
Routes:
GET/POST /{user_id}/underwriting/profile,GET/POST /{user_id}/floats/temporary_profile -
CRUD operations for float profiles
-
Temporary profile creation with TTL
-
-
Evaluation History:
-
Routes:
GET /{user_id}/underwriting/history,GET /{user_id}/underwriting/history/{evaluation_id} -
Retrieves recent and historical evaluations
-
-
Recalculation Requests:
-
Route:
POST /{user_id}/recalculate -
Publishes events to trigger async rule execution
-
-
Rulebook Management:
-
Routes:
GET /rulebooks,GET /rulebooks/changes -
Retrieves active rulebooks and audit trails
-
Error Handling
-
Upstream Service Failures: Returns 500 with error details, implements circuit breaker patterns
-
DynamoDB Errors: Retries with exponential backoff (via AWS SDK)
-
Validation Errors: Returns 400 with detailed error messages
-
Not Found: Returns 404 for missing users/resources
Environment Variables (lambdadispatch)
The following variables are required to initialize the lambdadispatch client, which the API Lambda uses to invoke the Rule Runner and Result Runner synchronously on the POST /instant path. Both are set by deploy/lambda.tf.
| Variable | Required | Purpose |
|---|---|---|
|
Yes |
AWS account ID used to construct Lambda ARNs for cross-function invocation |
|
Yes |
Deployment environment (e.g. |
Environment Variables (ML clients)
The following variables are required to initialize the Payback Predictor V2 model clients (initMLClients in cmd/api/main.go). All are set by deploy/lambda.tf.
| Variable | Required | Purpose |
|---|---|---|
|
Yes |
SageMaker endpoint name for the payback predictor v2 model. Consumed by |
|
Yes |
AWS Secrets Manager secret name containing the UXCam Data Access API credentials ( |
|
Yes |
Base URL of the Insight Service used to fetch next-payday data for the |
|
Yes |
AWS region of the Insight Service, used for SigV4 request signing. Consumed by |
Rule Runner Lambda
Entry Point: [cmd/rule-runner/main.go](cmd/rule-runner/main.go)
Purpose
Worker Lambda that executes individual rule evaluations. Fetches data from multiple services, runs rules against user data, and stores outcomes in DynamoDB.
Key Responsibilities
-
Data Gathering:
-
Fetches user data from User Service
-
Retrieves transaction history from Transactions Service
-
Gets active floats from Float Service
-
Retrieves ML insights from Insight Service
-
Fetches subscription status from Subscriptions Service
-
Gets payment information from Payments Service
-
-
Rule Execution:
-
Loads rulebooks from DynamoDB (with caching)
-
Filters rules by type (txns, insights, all)
-
Invokes individual Lambda rule functions
-
Collects rule results with features
-
-
Outcome Storage:
-
Writes RuleOutcome to DynamoDB with 32-day TTL
-
Stores features map for debugging
-
Records calc_status (OK, NODATA, CALCERR)
-
-
Result Runner Trigger:
-
Publishes event to Result Runner queue after all rules complete
-
-
Early-Advance Candidate + Notification payload:
-
Identifies the in-processing float and its collection payment that qualify for an early advance (most recent float
ACHSENT, no other outstanding, latest collection a T-1 day-before-ACH run —TOMORROW_FIRST_FLOAT, orTOMORROW_RETURNING_FLOATbehind the returning-float GrowthBook flag), via float-service collection history, and runsfloat_evaluation.EvaluateEarlyAdvanceover the run’s transactions. Only when the user clears does it feed RuleGoodStanding (and, via the result runner, the storedearly_advance_float_id/early_advance_payment_id/early_advance_day). -
When the user clears, it builds the
early_advance_eligiblenotification payload (email, float, day, rolloverend_date, payment) and carries it on the rule-run-completed event. It does NOT send the notification itself — the result runner does, once it confirms the user passed underwriting.
-
Error Handling & Retry Strategy
-
Rule Execution Failures: Individual rules can fail without failing entire evaluation
-
Service Timeouts: Returns CALCERR status, bypasses with cached data
-
SQS Retry: Message returns to queue if Lambda fails (max 1 retry)
-
DLQ Processing: Failed messages moved to DLQ for manual investigation
-
Sagemaker Errors: Gracefully degrades, marks insights as unavailable
Result Runner Lambda
Entry Point: [cmd/result-runner/main.go](cmd/result-runner/main.go)
Purpose
Aggregates individual rule outcomes into final eligibility decisions. Applies rulebook priority, superseding logic, and A/B test filtering.
Key Responsibilities
-
Outcome Retrieval:
-
Fetches all RuleOutcomes for user from DynamoDB
-
Loads rulebooks with caching
-
-
Evaluation Algorithm (ProcessFloatCheck):
-
Filters rulebooks by type (float vs loan)
-
Applies A/B test filtering (apply_to percentage)
-
Sorts by priority (descending)
-
Evaluates sequentially until approval or superseding rulebook
-
-
Result Storage:
-
Creates EvaluationResult with 32-day TTL
-
Stores rulebook_results array with individual outcomes
-
Records deciding_rulebook for approved users
-
Sets evaluation_status based on data quality
-
Persists
early_advance_float_id/early_advance_payment_id/early_advance_day(lifted from RuleGoodStanding’s outcome) for the live early-advance check
-
-
Early-Advance Notification:
-
When the float evaluation is approved (
float_results.approved) AND the rule runner carried an early-advance nudge on the event, sends the Iterableearly_advance_eligibleevent (andpayments.ach.early_advance_floatmetric). Gating on approval here — rather than in the rule runner, which does not know the final decision — ensures a user who cleared early advance but was denied by another rule is never notified. -
Requires the
SM_ITERABLE_NAMEsecret (Iterable API key); failures are logged and never fail the result run
-
-
CFI Evaluation:
-
Calculates float_rank and sub_rank
-
Determines eligible float tiers
-
Checks for limit increase eligibility
-
Updates FloatProfile if increase detected
-
-
Event Publishing:
-
Publishes evaluation complete events
-
Triggers Segment tracking for CFI changes
-
Float Created Handler Lambda
Entry Point: [cmd/float-created-handler/main.go](cmd/float-created-handler/main.go)
Purpose
Event handler that creates permanent historical evaluation records when a float or loan is taken. Helps with compliance and preserves CFI calculations data.
Key Responsibilities
-
Event Processing:
-
Receives
float.createdevents from EventBridge via SQS -
Extracts float_id, user_id, amount from event payload
-
-
Historical Record Creation:
-
Retrieves corresponding EvaluationResult from DynamoDB
-
Creates HistoricalEvaluation entity (permanent, no TTL)
-
Stores complete evaluation snapshot:
-
Float/loan evaluation results
-
Rulebook outcomes
-
CFI state at time of float
-
Amount and product taken
-
-
-
Compliance:
-
Preserves exact evaluation used for credit decision
-
Enables dispute resolution and auditing
-
-
CFI Support:
-
Historical floats used to calculate float_rank
-
Enables "highest float ever taken" tracking
-
Supports reactivating user limit determination
-
-
Rules Re-run:
-
After the historical eval is preserved, emits an
underwriting_recalculate_userevent (sourceunderwriting.api) to the FloatMe event bus -
This is the same event the API’s
POST /{user_id}/recalculateendpoint emits, so it is matched byrule_runner_event_ruleand triggers a fresh Rule Runner evaluation for the user -
Fires for every created float — including when no prior eval existed to preserve — so the user’s evaluation always reflects the newly created float
-
Environment Variables
| Variable | Description |
|---|---|
|
Underwriting single-table location |
|
Transactions service (primary account lookup) |
|
Region of the FloatMe event bus used to emit the recalculate event |
IAM Permissions
-
dynamodb:BatchGetItem/GetItem/PutItem/Queryon the underwriting table -
sqs:ReceiveMessage/DeleteMessage/GetQueueAttributeson the float-created SQS tap -
events:DescribeEventBus/PutEventson the FloatMe event bus (recalculate event) -
execute-api:Invokeon the transactions service
Error Handling
-
Missing Evaluation: Logs "no loan evaluation found", skips the historical record, and still emits the recalculate event
-
DynamoDB Errors: Retries with backoff
-
Malformed Events: Logs and moves to DLQ
-
Recalculate Emit Failure: Returns an error so the SQS message is not silently dropped
-
Service Timeouts: Retries with exponential backoff
Profile Handler Lambda
Entry Point: [cmd/profile-handler/main.go](cmd/profile-handler/main.go)
Purpose
Creates default float profiles for newly signed-up users. Ensures all users have a starting configuration for float eligibility.
Key Responsibilities
-
Event Processing:
-
Receives
user.signup.completedevents -
Extracts user_id from event payload
-
-
Profile Creation:
-
Checks if profile already exists (idempotency)
-
Creates default FloatProfile:
-
Floats $10 and $20 enabled
-
Floats $30-$100 disabled
-
Standard loan tiers
-
cfi_enabled: true
-
-
Writes to DynamoDB with timestamp
-
-
Idempotency:
-
Skips creation if profile already exists
-
Prevents duplicate profiles from event replays
-
API Lambda IAM Permissions
The API Lambda has the following IAM policy statements:
| Actions | Resources |
|---|---|
|
underwriting DynamoDB table and its indexes |
|
FloatMe EventBridge bus |
|
Payments, Transactions, Float, LOC, User, Subscriptions service API Gateway endpoints |
|
GrowthBook secret |
|
Rule Runner and Result Runner Lambda functions (for |
Monitoring & Observability
CloudWatch Metrics
All Lambdas emit standard metrics:
-
Invocations: Total invocation count
-
Duration: Execution time (ms)
-
Errors: Error count
-
Throttles: Throttling events
-
ConcurrentExecutions: Active executions
Datadog Metrics
Custom metrics tracked:
-
underwriting.evaluation.duration- Evaluation processing time -
underwriting.rule.execution.duration- Individual rule execution time -
underwriting.cfi.limit.increased- CFI limit increase events -
underwriting.cfi.limit.decreased- CFI limit decrease events -
underwriting.sagemaker.latency- ML inference latency -
underwriting.service.call.duration- Downstream service latency
CloudWatch Logs
Log Structure: * Level: DEBUG, INFO, WARN, ERROR * Request ID: AWS request ID for tracing * User ID: User being evaluated * Correlation ID: Event correlation across Lambdas
Key Log Events: * Rule execution start/completion * Service call requests/responses * DynamoDB operations * Error stack traces * CFI calculations
See Also
-
System Architecture - Overall system design
-
Rule Engine - Evaluation logic
-
DynamoDB Schema - Data structures
-
Deployment - Terraform and deployment processes