AmexCallback Lambda Function
Quick Reference
- Function Name:
payment3-amex-callback-${BRANCH} - Handler:
amexcallback.lambda_handler - Runtime: Python 3.12 (Docker Image)
- Trigger: API Gateway (POST /amex/callback)
- Template.yaml: Lines 244-286
Function Overview
The AmexCallback function processes American Express payment callbacks. It saves callback records to AmexCallbackRecordTable and invokes ProcessPaidAmexOrderInternal for successful payments. This function uses the BaseCallbackProcessor pattern shared with Wallet and BankApp callbacks.
Entry Point
File: functions/callback/amexcallback.py
Handler: lambda_handler(event, _)
def lambda_handler(event, _):
"""
Record Amex callback.
"""
processor = None
try:
print(f"Processing amex callback event: {json.dumps(event)}")
processor = BaseCallbackProcessor(
event=event,
record_table_class=AmexCallbackRecordTable,
function_name="Amex"
)
processor.save()
response = processor.response
print(f"Amex callback processed successfully: {json.dumps(response)}")
if processor.success:
processor.call_processpaid("amex-order-internal")
return response
except Exception as e:
error_msg = f"Error processing amex callback: {e} {errorString()}"
print(error_msg)
# Extract orderId and chargeId for error logging
orderId = None
chargeId = None
if processor:
try:
orderId = processor.order_id
chargeId = processor.payment_id
except (AttributeError, KeyError):
# Processor may not have these attributes if initialization failed
pass
# Add context to Sentry
with sentry_sdk.push_scope() as scope:
if orderId:
scope.set_tag("orderId", orderId)
if chargeId:
scope.set_tag("chargeId", chargeId)
scope.set_tag("function", "amexcallback")
scope.set_context("callback_processor", {
"has_processor": processor is not None,
"chargeId": chargeId,
"orderId": orderId,
})
sentry_sdk.capture_exception(e)
# Log to callback error log table
log_callback_error(
error=e,
function_name="amexcallback",
event=event,
orderId=orderId,
chargeId=chargeId,
response_data=None,
metadata={"errorString": errorString()}
)
# Send email notification to admin
try:
send_callback_error_email(
error=e,
function_name="amexcallback",
orderId=orderId,
chargeId=chargeId,
event=event
)
except Exception as email_error:
print(f"Failed to send error email: {email_error}")
# Don't fail the whole function if email fails
return {
"statusCode": 500,
"headers": {"Content-Type": "application/json"},
"body": json.dumps(
{
"success": False,
"error": str(e),
"message": "Failed to process amex callback",
}
),
}
Event Structure
API Gateway Event
Path: POST /amex/callback
Auth: NONE (public endpoint - called by payment gateway)
Request Body (JSON):
{
"orderId": "482500007436",
"paymentId": "pay_amex_1234567890",
"success": true,
"amount": 2339.0,
"userId": "b5f392f7-6d89-433c-b24f-bf6a772cab1a",
"message": "Payment successful"
}
Required Fields:
orderId- Villa order ID (required)paymentId- Payment gateway payment ID (required)success- Payment success status: true or false (required)userId- Villa user ID (required)amount- Paid amount (optional)message- Optional message
Response (Success):
{
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": "{\"success\": true, \"message\": \"Amex callback recorded successfully\", \"orderId\": \"...\", \"paymentId\": \"...\", \"amount\": ...}"
}
DynamoDB Tables
AmexCallbackRecordTable
Table Name: payment3-amex-callback-record-{BRANCH}
Region: ap-southeast-1
PynamoDB Model:
class AmexCallbackRecordTable(Model):
class Meta:
table_name = f"payment3-amex-callback-record-{BRANCH}"
region = "ap-southeast-1"
orderId = UnicodeAttribute(hash_key=True)
paymentId = UnicodeAttribute()
success = BooleanAttribute()
userId = UnicodeAttribute()
message = UnicodeAttribute(null=True)
created_at = UnicodeAttribute()
updated_at = UnicodeAttribute()
event = JSONAttribute(null=True)
body = JSONAttribute(null=True)
amount = NumberAttribute(null=True)
def __post_init__(self):
if not self.created_at:
self.created_at = datetime.now().isoformat()
if not self.updated_at:
self.updated_at = datetime.now().isoformat()
Key Fields: Same structure as WalletCallbackRecordTable
- Hash Key:
orderId(UnicodeAttribute) paymentId- Payment gateway payment IDsuccess- Payment success statususerId- Villa user IDmessage- Optional messageamount- Paid amount (optional)event- Full event data (optional)body- Request body (optional)created_at- Creation timestampupdated_at- Update timestamp
Lambda Invocations
ProcessPaidAmexOrderInternal
Function: payment3-process-paid-amex-order-internal-${BRANCH}
Invoked When: processor.success is True
Payload: Full request body (JSON string)
Invocation Type: Event (asynchronous)
Processing Flow
Same as WalletCallback - uses BaseCallbackProcessor pattern:
- Create BaseCallbackProcessor with AmexCallbackRecordTable
- Validate required fields
- Save to AmexCallbackRecordTable
- Invoke ProcessPaidAmexOrderInternal if success is True
- Return JSON response
Error Handling
Same error handling as WalletCallback:
- Validation errors logged to CallbackErrorLogTable
- Sent to Sentry with context tags
- Error email sent via SES
- Returns 500 error response
IAM Policies
From template.yaml (lines 253-273):
DynamoDBWritePolicyforAmexCallbackRecordTable(line 254-255)DynamoDBReadPolicyfororder-table-dev(line 256-257)DynamoDBCrudPolicyforpayment3-card-payment-record-master(line 258-259)LambdaInvokePolicyforProcessPaidAmexOrderInternal(line 260-261)AWSSecretsManagerGetSecretValuePolicyfor kbank-dev (line 262-263)AWSSecretsManagerGetSecretValuePolicyfor kbank-prod (line 264-265)DynamoDBWritePolicyforCallbackErrorLogTable(line 266-268)SESCrudPolicyfor sending error emails (line 269-271)
Dependencies
External Lambda Functions
payment3-process-paid-amex-order-internal-${BRANCH}- Process paid Amex orders (invoked)
DynamoDB Tables
payment3-amex-callback-record-${BRANCH}- Callback records (write)order-table-dev- Order data (read)payment3-card-payment-record-master- Master payment records (read)payment3-callback-error-log-${BRANCH}- Error logs (write)
AWS Services
- SES: Send error notification emails
Testing
Test Event Example
{
"body": "{\"orderId\": \"482500007436\", \"paymentId\": \"pay_amex_123\", \"success\": true, \"amount\": 2339.0, \"userId\": \"b5f392f7-6d89-433c-b24f-bf6a772cab1a\", \"message\": \"Payment successful\"}"
}
Code Structure
File Organization:
functions/callback/
├── amexcallback.py # Main handler
└── src/
├── base_callback_processor.py # Base processor (shared)
└── amexCallbackRecordTable.py # Amex callback table
Related Functions
- ProcessPaidAmexOrderInternal - Processes paid Amex orders
- WalletCallback - Similar callback handler
- BankAppCallback - Similar callback handler
References
- Template.yaml: Lines 244-286
- Related Functions: ProcessPaidAmexOrderInternal, WalletCallback, BankAppCallback
- Base Processor:
src/base_callback_processor.py