
Building Human-in-the-Loop Agentic Workflows with Amazon Bedrock, MCP, and Slack Approval Gates
Would you trust an AI agent to wire $99,999 from your bank account without asking you first? I wouldn't. And neither should any enterprise.
That's the exact problem I set out to solve. We hear a lot about Agentic AI these days AI systems that don't just respond to prompts but actually take actions on your behalf. They book meetings, execute trades, trigger deployments, move money. The promise is incredible. But here's what nobody talks about enough:
What happens when the agent is wrong?
What happens when it confidently decides to execute a suspicious $99,999 wire transfer to an unknown account? What if there's no one standing between that decision and a catastrophic mistake?
That's where Human-in-the-Loop (HITL) comes in. And that's exactly what I built a fully serverless, production-grade HITL Agentic AI workflow on AWS that knows when to act and when to stop and ask a human.
What Exactly Did I Build?
I built an AI agent orchestration system where:
- An AI agent (powered by Amazon Bedrock) receives financial transaction requests
- It analyzes the risk level of each transaction
- Low-risk actions get processed automatically
- High-risk or suspicious actions get paused and a real human gets notified on Slack with an interactive Approve/Deny button
- The human reviews, makes a decision, and the system either executes or blocks the transaction
- Every single state transition is tracked in DynamoDB, and the final results are stored in Amazon S3
Think of it as giving your AI agent the power to act but with a safety net that ensures a human is always in control when it matters most.
The Architecture Simple, Serverless, and Scalable

Here's how every piece fits together:
The Flow:
1
2
3
4
Request → API Gateway → Lambda (Orchestrator) → Bedrock (AI Agent) → Human Review (Slack) → S3 (Data Store)
↓ ↓ ↓
DynamoDB IAM CloudWatch
(State Store) (Security) (Monitoring)
Services and Their Roles:
| AWS Service | Role |
|---|---|
| Amazon API Gateway | Entry point — receives incoming transaction requests and Slack callback responses |
| AWS Lambda | The brain — two functions orchestrate the entire workflow |
| Amazon Bedrock | AI agent that analyzes transaction risk |
| Amazon DynamoDB | Tracks every request's state (PENDING → EXECUTED / DENIED) |
| Amazon S3 | Stores final transaction records |
| AWS IAM | Least-privilege security for every component |
| Amazon CloudWatch | Monitoring and logging across the pipeline |
| Slack | Human interface — where approvers receive interactive notifications |
The beauty of this architecture? Zero servers to manage. It scales automatically, costs almost nothing at rest, and every component is decoupled. If Slack goes down, the request just stays in PENDING state in DynamoDB until someone acts on it. No data loss. No race conditions.
The Build Step by Step
Let me walk you through how I actually built this. No hand-waving. Real commands, real outputs.
Step 1: Setting Up the Foundation
Everything was built from AWS CloudShell no local setup needed, no dependency headaches.
First, I created the IAM role for Lambda with the exact permissions needed nothing more, nothing less:
- DynamoDB read/write access for state management
- S3 put access for storing completed transactions
- Bedrock invoke access for the AI agent
- CloudWatch logs for observability
Step 2: Building the Lambda Functions
I created two Lambda functions, each with a very specific job:
🔹 HITL-Approval-Sender - The Orchestrator
This is the function that receives the incoming transaction request, generates a unique request ID, stores the initial state in DynamoDB as PENDING, calls Bedrock for risk analysis, and sends an interactive approval message to Slack.
🔹 HITL-Callback-Handler - The Decision Executor
This function sits behind API Gateway and handles the callback when a human clicks Approve or Deny on Slack. It updates DynamoDB, generates a transaction ID (if approved), stores the record in S3, and sends a confirmation message back to Slack.

Both functions run on Python 3.11, with 256MB memory and a 10-second timeout more than enough for this workflow.
Step 3: The API Gateway & Slack Integration
Here's where it gets interesting. I needed a public HTTPS endpoint that Slack could call when someone clicks a button. So I set up an API Gateway REST API with a
/slack-callback POST route, integrated it with the HITL-Callback-Handler Lambda, deployed it to a prod stage, and generated the callback URL.
The callback URL looks like this:
1
https://8wk5p8u5oe.execute-api.ap-south-1.amazonaws.com/prod/slack-callback
This URL was then configured in the Slack app's Interactivity settings, so whenever an approver clicks a button, Slack sends the payload right back to our Lambda.
Testing The Moment of Truth
This is where I had the most fun. I tested two scenarios that represent real-world financial operations:
Test 1: A Legitimate Wire Transfer ($5,000)
I invoked the Lambda with a standard wire transfer request:
1
2
3
4
5
aws lambda invoke \
--function-name HITL-Approval-Sender \
--cli-binary-format raw-in-base64-out \
--payload '{"account_id":"98765","amount":5000,"action_type":"Wire Transfer"}' \
/tmp/test2.json
What happened:
The Lambda returned status
200 with pending_approval. A unique request ID was generated: 8d8281f5-20e6-4803-833f-2fc70c442846.
I immediately checked DynamoDB:
1
2
3
aws dynamodb get-item \
--table-name AgentStateTable \
--key '{"RequestId":{"S":"8d8281f5-20e6-4803-833f-2fc70c442846"}}'
Result: Status = PENDING. The system was waiting for a human.
Then I opened Slack. There it was a beautiful interactive message:
Agent Action Needs Approval
- Request ID:
8d8281f5-20e6-4803-833f-2fc70c442846 - Type: Wire Transfer
- Amount: $5,000.00
- Details: Transfer $5,000.00 to account 98765
- [✅ Approve] [❌ Deny]
I clicked ✅ Approve.
Checked DynamoDB again:
Result: Status = EXECUTED | ProcessedBy = poojabhavani19 | TransactionId = TXN-8D8281F5
The transaction went through. The human approved. The system executed. Exactly as designed.

Test 2: A Suspicious Transfer ($99,999) The Real Test
Now for the scenario that actually matters. What happens when something looks wrong?
1
2
3
4
5
aws lambda invoke \
--function-name HITL-Approval-Sender \
--cli-binary-format raw-in-base64-out \
--payload '{"account_id":"SUSPICIOUS-999","amount":99999,"action_type":"Suspicious Transfer"}' \
/tmp/test3.json
Again,
pending_approval. Request ID: 1d4840af-3ce9-47b0-ab7c-d71df71584bc.Slack lit up:
Agent Action Needs Approval
- Request ID:
1d4840af-3ce9-47b0-ab7c-d71df71584bc - Type: Suspicious Transfer
- Amount: $99,999.00
- Details: Transfer $99,999.00 to account SUSPICIOUS-999
This time, I clicked ❌ Deny.
Checked DynamoDB:
Result: Status = DENIED | ProcessedBy = poojabhavani19 | TransactionId = None
$99,999 saved. The AI wanted to act. The human said no. The system respected that decision instantly.

Final State Both Transactions
A full scan of the DynamoDB table tells the complete story:


Two transactions. Two different decisions. Both handled correctly. That's Human-in-the-Loop working exactly as it should.
Why This Matters The Bigger Picture
Let's zoom out for a moment.
Agentic AI is the future. There's no debating that. But we're entering a phase where AI agents will be making decisions that have real-world consequences financial transactions, infrastructure changes, healthcare recommendations, legal document processing.
The organizations that will succeed with Agentic AI won't be the ones that give their agents unlimited power. They'll be the ones that build intelligent guardrails.
This project demonstrates a pattern that can be applied to:
- Financial Services – Transaction approvals, fraud detection, compliance checks
- Healthcare – Treatment plan approvals, prescription verification
- DevOps – Infrastructure changes, production deployments, access grants
- Legal – Contract approvals, document classification
- E-commerce – High-value order verification, refund processing
The pattern is always the same: Let the AI do the heavy lifting, but keep a human in the loop for decisions that matter.
Key Takeaways
1. Serverless is the perfect fit for HITL workflows. You don't need containers or EC2 instances for this. Lambda + DynamoDB + API Gateway gives you a workflow that scales to zero when idle and handles bursts effortlessly.
2. Slack makes an incredible human interface. Interactive messages with buttons turn approval workflows from "check your email and fill out a form" to "tap a button on your phone." The response time goes from hours to seconds.
3. State management is everything. DynamoDB as a state store means every request has a clear lifecycle: PENDING → EXECUTED or DENIED. There's no ambiguity. There's no "what happened to that request?"
4. Security cannot be an afterthought. Every Lambda function has the minimum permissions it needs. API Gateway validates inputs. IAM policies are scoped to specific resources. In a production system handling financial data, this isn't optional.
5. The AI agent is powerful because it has boundaries. This might sound counterintuitive, but an AI agent that knows when to pause and ask for help is more trustworthy and ultimately more useful than one that blindly executes everything.
What's Next?
This project is a foundation. Here's where I'd take it next:
- Amazon Bedrock Agents for more sophisticated risk scoring and natural language reasoning
- AWS Step Functions for complex multi-step approval chains
- Amazon SNS as an alternative notification channel for email/SMS approvals
- Amazon QuickSight dashboards for approval analytics and audit trails
- Multi-approver workflows where high-risk actions require 2+ approvals
Final Thoughts
I built this project because I believe that the future of AI isn't about removing humans from the loop it's about putting them in the right part of the loop.
An AI agent that can analyze thousands of transactions per minute is incredible. But an AI agent that knows to pause on that one suspicious $99,999 transfer and ask a human to take a look? That's the agent I want running in production.
If you're building Agentic AI systems on AWS, I hope this gives you a practical blueprint. The technology is all there Bedrock for intelligence, Lambda for orchestration, DynamoDB for state, Slack for human interaction. The magic is in how you connect them.
Trust your AI. But verify with humans. That's not a limitation it's a superpower.
Tech Stack Summary
1
2
3
4
5
6
7
8
├── Amazon Bedrock → AI Agent (Risk Analysis)
├── AWS Lambda (x2) → Orchestration & Callback Processing
├── Amazon API Gateway → REST API (Request Ingestion + Slack Callbacks)
├── Amazon DynamoDB → State Management (Request Lifecycle)
├── Amazon S3 → Data Store (Completed Transactions)
├── AWS IAM → Security (Least-Privilege Policies)
├── Amazon CloudWatch → Monitoring & Logging
└── Slack (Interactive) → Human-in-the-Loop Interface
Built with ☕ and a lot of CloudShell tabs in ap-south-1 (Mumbai).
If this project resonated with you, I'd love to connect and hear how you're thinking about human-AI collaboration in your own work.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article