The Vision
Troxy is the control layer between AI agents and the real world of payments. Not a payment company. Not a bank. A smart middleware that enforces human intent before money moves.
One sentence

Troxy is the proxy you trust — a policy enforcement layer that sits between your AI agents and your payment methods, making sure agents only spend what you actually authorized.

The Cloudflare Analogy

The clearest way to explain Troxy is through an analogy that resonates immediately with both technical and non-technical audiences:

Cloudflare doesn't replace the internet. It sits in front of your website and makes sure only the right traffic gets through. It filters, it enforces, it logs — invisibly, in the background.

Troxy doesn't replace your bank or your cards. It sits in front of your payments and makes sure your agents only spend what you actually authorized. Infrastructure you trust, invisibly working in the background.

The Core Insight

AI agents are being given access to real money with no guard rails. The problem isn't the AI companies — it's that there's no layer between the agent and the payment. Troxy is that layer.

Without Troxy

Agent has direct access to your payment method. No limits, no checks, no audit trail. Agent hallucinates, gets prompt-injected, or loops — your money is gone.

With Troxy

Every payment goes through your rules first. Budget envelopes, merchant filters, approval flows. Full audit trail. You stay in control without lifting a finger.

What Troxy Is NOT

This is important to be clear about — especially when talking to investors or enterprise customers:

  • Not a payment processor — Troxy never touches card numbers or moves money
  • Not a bank or fintech — no financial license required
  • Not trying to compete with Visa, Stripe, or PayPal — we sit on top of them
  • Not an AI company — we enforce policy, we don't replace the agent
Key positioning

Troxy is a software policy engine. This keeps us out of financial regulation and lets us move fast. The moment we touch money directly, everything changes. We never do that.


The Problem
Three distinct failure modes make AI agent payments dangerous today.
Hallucination risk

An agent misreads a task and places 200 identical orders. Or loops on a procurement workflow draining your account overnight. No hard stop exists.

Prompt injection

A malicious website embeds hidden instructions. Your agent reads it, and is hijacked to redirect payments or exfiltrate card data. OWASP's #1 LLM threat in 2025.

Zero auditability

Your AI spent $4,800 last month. On what? Which agent? Authorized by whom? Nobody knows. Finance teams are flying blind on agentic spend.

Real Scenarios That Motivated This

Scenario 1 — The Over-Spending Agent

User tells Claude: "Book me a hotel in Amsterdam for next week, budget $200." Agent finds a hotel at $220 — just 10% over. Without Troxy, it charges the card. With Troxy: agent hits the budget envelope limit, user gets a push notification: "Your travel agent wants to charge $220 to Marriott — $20 over your budget. Approve?" User taps yes. Done.

Scenario 2 — Wrong Card for Wrong Purpose

Gilad has a business Amex and a personal Visa. He asks his agent to buy groceries. Without Troxy, the agent uses whichever card is configured — probably the wrong one. With Troxy: the card alias "Gilad's Groceries" (Visa ···1234) is mapped to the grocery category. Agent automatically uses the right card. No confusion, clean expense reports.

Scenario 3 — Romi's Fruits (Multi-User)

Romi uses a separate agent to buy fruits. Gilad wants to give her a $50/month budget, on the Mastercard ending in 5678, for groceries only. Troxy makes this trivial: create alias "Romi's Fruits", assign Mastercard ···5678, set $50 envelope, restrict to grocery merchants, assign to Romi Agent. That's it. Every purchase Romi's agent makes goes through this policy.


The Solution

Troxy intercepts every payment tool call an agent makes, evaluates it against the user's policies, and either passes it through, blocks it, or escalates it to the human for approval. The agent never knows Troxy is in the middle.

01
Agent triggers a payment
Troxy intercepts
Policy engine evaluates in <100ms
Decision
Pass / Block / Escalate
Logged
Full audit trail with context

The Budget Envelope Feature

One of the most powerful and intuitive features. Troxy lets you treat any credit card like a smart prepaid debit card — without changing anything about the actual card.

# Your rule, in plain English:
Card ···1234 → $200 budget for travel agent this month
Card ···5678 → $50/week for shopping, groceries only
Card ···9012 → blocked from all agents until manually unlocked

# Agent tries to exceed budget:
Agent: "charge $240 to card ···1234"
Troxy: envelope check → $200 limit → BLOCK
Troxy: sends push notification to user
User: approves or declines within 10 min
# No response → auto-decline
The key insight

The credit card behind it does whatever it does. Troxy doesn't care. It's a policy gate that enforces the envelope before the real charge ever fires. The user experiences it as a debit card. The bank sees a normal credit card charge.


Name & Brand

Why Troxy

The name went through an extensive search process. Key constraints: must work in English and Hebrew, easy to pronounce globally, available as a .ai domain, and the meaning must be embedded in the name itself.

Troxy = Trust + Proxy

The two core concepts of the entire platform compressed into one five-letter word. Trust — what users need to feel about their money. Proxy — what Troxy technically is, sitting between the agent and the payment. Short, punchy, easy to say in any language, and immediately legible to anyone in the developer or fintech world.

Domain

troxy.ai — confirmed available as of March 2026. Register immediately before squatters pick it up.

Tagline

"The proxy you trust." — covers both halves of the name and the core value proposition in four words.

Brand Principles

  • Professional but not boring — infrastructure credibility without the enterprise stiffness
  • Developer-first aesthetics — clean, functional, no unnecessary decoration
  • Trust signals everywhere — the product is literally about trust, the brand must reflect it
  • Color: teal (#0a9e88) — stands out from the sea of blue fintech brands

What Are AI Agents
Understanding the agent landscape is critical for knowing who Troxy's users are and how the product fits in.

The Difference Between Chat and Agents

Regular AI (chat)

You type → Claude responds → done. No action in the world. Output is text only.

AI Agent

Claude is given tools — functions it can actually call. It can search the web, send emails, book flights, charge cards. Real actions, real consequences.

How Agents Call Tools — MCP

MCP (Model Context Protocol) is the standard Anthropic created for how AI agents discover and call tools. Think of it like USB — before USB, every device had a different connector. MCP is USB for AI tools.

Any service that wants to be usable by agents publishes an MCP server. When an agent is configured to use Stripe's MCP server, it can call create_payment() directly. No human confirmation needed.

# Agent config (Claude Desktop, Cursor, etc.)
{
  "mcpServers": {
    "stripe": { "url": "https://mcp.stripe.com", "apiKey": "sk_live_..." },
    "gmail":  { "url": "https://gmail.mcp.google.com", "token": "ya29..." }
  }
}

Four Categories of Agents

CategoryExamplesTroxy relevance
Consumer agents Claude, ChatGPT, Perplexity, Devin, AutoGPT Free tier users, individual consumers
Developer frameworks LangChain, CrewAI, AutoGen, LlamaIndex Developers building their own agents
Internal company agents Procurement bots, finance automation, HR agents Biggest enterprise opportunity — run 24/7 with no human watching
Custom Claude agents Anyone with Claude Projects or API access Zero barrier to create — anyone is a potential user
The key insight for sales

Internal company agents are the most dangerous and the most underserved. They run 24/7, nobody is watching, and they have real budget access. This is the strongest enterprise pitch.

Anyone Can Create an Agent Today

This is important to understand — the barrier to creating an agent is essentially zero. Opening Claude and typing this creates an agent:

# This is all it takes to create an agent:
"You are a travel booking agent. When I ask you to book travel,
use the Stripe MCP to pay, the Gmail MCP to send confirmations,
and Google Calendar MCP to add it to my calendar."

# Claude will now call real tools, with real consequences,
# every time the user asks it to book something.

The Core Bet
This is the single sentence that defines what Troxy is and isn't. Everything — architecture, scope, GTM — flows from this.
The bet

Troxy intercepts any purchase made through an MCP payment tool, regardless of which AI agent makes it or which payment provider receives it. We're betting that MCP becomes the standard protocol for AI agent commerce. That's it.

What this means in practice

Agent Payment MCP Troxy works?
Claude DesktopStripe MCP✅ Yes
CursorStripe MCP✅ Yes
Custom GPT-4 agentStripe MCP✅ Yes
OpenAI agentPayPal MCP✅ Yes
Any agentShopify MCP✅ Yes
Browser agent clicking "Buy"No MCP — direct browser❌ Not in scope
Agent calling Stripe REST API directlyNo MCP — raw API❌ Not in scope
The one constraint

The payment provider must have an MCP server. Today that means primarily Stripe — which is why MVP targets Stripe. PayPal, Shopify, and Square MCP servers are coming but not all production-ready yet. We add them as they mature. This is not a permanent limitation — it's a timing one.

Why Troxy is agent-agnostic

The daemon intercepts at the MCP config layer — not at the agent layer. It rewrites the config file that tells the agent where to find payment tools. The agent reads the config, calls what it thinks is Stripe, and hits Troxy instead. The agent never knows.

# The agent's MCP config (after troxy init):
{
  "mcpServers": {
    "stripe": {
      "url": "http://localhost:4242/stripe"   ← Troxy daemon
    }
  }
}

# The agent thinks this IS Stripe.
# It doesn't matter if the agent is Claude, GPT-4, Gemini,
# a LangChain script, or anything else.
# Whatever calls this URL — Troxy catches it.

The pitch framing

How to say this to investors

"Troxy works with any AI agent that uses MCP for payments. We're not betting on Claude winning or GPT-4 winning. We're betting on MCP winning as the standard protocol — which Anthropic created, OpenAI supports, and every major agent framework is adopting. As MCP adoption grows, every new agent automatically becomes a potential Troxy user. We don't chase agents. Agents come to us."

What's out of scope — and the future path

Scenario Why out of scope now Future path
Browser agents clicking "Buy"Different architecture entirely — needs browser extension, not MCP proxyChrome extension (in More Ideas)
Agents calling payment APIs directlyNo MCP layer to intercept — would need SDK-level integrationPayment provider partnership (V4)
PayPal / Shopify / SquareMCP servers not fully production-ready yetAdd as each provider's MCP server matures — same daemon code, new entry in payment_mcps.go
How Troxy Works

The Config Rewrite

When Troxy installs, it rewrites the MCP config files so all payment tool calls go to Troxy first instead of directly to the payment provider:

# Before Troxy install:
{ "stripe": { "url": "https://mcp.stripe.com" } }

# After npx troxy init:
{ "stripe": { "url": "http://localhost:4242/stripe" } }

# Agent thinks it's talking to Stripe.
# It's actually talking to Troxy on localhost.
# Troxy decides pass/block, then forwards if approved.

Full Transaction Flow

1 Agent calls stripe.create_payment(amount=299, merchant="Ahrefs")
2 Request hits Troxy daemon on localhost:4242
3 Troxy enriches with context: which agent, which user, which session
4 Policy engine evaluates: amount vs envelope, merchant vs allowlist, card routing
5a ALLOW → forwards to real Stripe MCP → charge happens → logged
5b BLOCK → request dies → user notified with reason → logged
5c ESCALATE → request held → push notification sent → user has 10 min to approve

Critical detail

The agent has zero awareness that Troxy is in the middle. It calls what it thinks is Stripe. This means zero integration effort for the end user — just point the config at Troxy and everything works.

The Daemon Process

Troxy runs as a background process on the user's machine — exactly like Dropbox, antivirus software, or Cloudflare WARP. It starts automatically on login, runs silently, and does its job without the user thinking about it.

# CLI commands:
troxy daemon start     # start (auto on boot)
troxy daemon stop      # stop
troxy daemon status    # check if running
troxy logs             # tail local logs
troxy policy list      # view active rules
troxy update           # update to latest version

Card Aliases — The Real Number Stays Hidden

Users never see card numbers in Troxy. They create aliases that map to real cards stored with their payment provider:

AliasReal card (never shown)Purpose
Gilad's GroceriesVisa ···1234Personal grocery shopping
Romi's FruitsMastercard ···5678Romi's grocery agent, $50/mo limit
Work ExpensesAmex ···9012SaaS, travel, office supplies only

If the user gets a new card, they update the alias once. All policies attached to the alias continue working unchanged.


Core Features
Policy Engine

IF/AND/THEN rule system. Set rules per agent, per card alias, per merchant category. Amount limits, time windows, merchant allowlists. No code required — pure UI.

Budget Envelopes

Virtual spending limits per card alias. Monthly, weekly, or per-task budgets. When envelope runs out, agent is blocked. Resets automatically on schedule.

Smart Card Routing

Multiple cards, intelligent routing. Business purchases go to Amex, groceries go to Visa, Romi's purchases go to her card. Automatic, based on policy rules.

Human Approval Flows

Anything exceeding thresholds gets paused. Push notification, email, or Slack. User has configurable window (5min–1hr) to approve or block. No response = auto-decline.

Centralized Audit Trail

Every transaction, every policy decision, every block — logged with full context. Which agent, which task, which card, which policy triggered. Exportable for accounting.

Prompt Injection Shield

Malicious websites trying to hijack agent payments hit the policy wall first. Even if the agent is compromised, the policy layer enforces the rules regardless.

The "Notify Before Declining" Feature

This is one of the most important and differentiating features. Instead of a hard block, users can set a policy that says: "if the expense is greater than X% over budget, notify me before auto-declining."

How it works

Policy: "If amount exceeds budget by more than 10% — notify me, wait 10 minutes for approval, then auto-decline."

Agent tries to charge $220 against a $200 envelope (10% over):

  1. Troxy intercepts — amount exceeds envelope by exactly 10%
  2. Policy match: "notify before declining"
  3. Push notification sent: "Travel agent wants $220 for Marriott — $20 over budget. Approve?"
  4. User has 10 minutes to tap Approve or Block
  5. No response → auto-decline, agent gets a rejection

This turns Troxy from a rigid blocker into a smart assistant. The agent doesn't just get rejected — the human gets a chance to override for legitimate one-off cases.

Future Features (Roadmap)

FeatureDescriptionPriority
Time-based rulesNo spending after midnight, weekend limitsV2
Velocity rulesMax 3 transactions per hour per agentV2
Multi-currency envelopesBudget in USD but card charges in EURV3
Family/team plansGive Romi her own login with limited permissionsV2
Anomaly detectionML-based: this doesn't look like this agent's normal behaviorV3
LLM intent verification"Does this charge semantically match the original task?"V3
Monthly spend reportsAuto-emailed PDF with all agent spendingV2
Payment provider integrationsStripe/PayPal require Troxy token — cryptographic guaranteeV4

Dashboard UX

The dashboard is Cloudflare-style — clean, information-dense, immediately actionable. Every screen answers one question in under 3 seconds.

PageQuestion it answersKey elements
OverviewIs everything okay right now?Spend summary, recent activity, pending approvals, blocked count
CardsHow much budget do I have left?Card aliases, budget progress bars, agent assignments
PoliciesWhat are my rules?IF/AND/THEN rule list, color-coded by type (allow/notify/block)
AgentsWhat can each agent do?Registered agents, permissions, spend history per agent
ActivityWhat happened and why?Full audit log, filter by agent/card/date, receipt per transaction

Approval Notification

When a transaction needs approval, the user gets a push notification/email with one-tap actions. No need to open the dashboard:

Troxy — Action Required
Travel Agent wants to charge $340 to Airbnb
Card: Work Expenses ···9012 · 10 minutes to respond
Approve Block

Tech Stack for Dashboard

ComponentTechnologyWhy
FrameworkNext.jsAWS CloudFront + S3. Static export. All data fetching client-side. Fully managed by Terraform.
HostingS3 + CloudFrontAlready in AWS, Terraform managed, GitHub Actions deploys on push, free at MVP scale
AuthAuth0 or CognitoOAuth, Google login, token management
Real-timeWebSocketLive approval queue, transaction feed
Domaindashboard.troxy.aiClean subdomain, DNS already on Cloudflare, CloudFront handles SSL automatically

Policy Engine

The policy engine is the brain of Troxy. Every transaction is evaluated against a user's rules before being passed, blocked, or escalated.

Rule Structure

Every policy is an IF/AND/THEN statement. No code required — pure UI builder:

IF   agent is        [Romi Agent]
AND  card is         [Romi's Fruits]
AND  category is     [Groceries]
AND  amount is       [under $50]
THEN [Allow automatically]

Policy Types

TypeColorBehaviorExample
AllowGreenAuto-approve, no notificationRomi groceries under $50
NotifyAmberSend push/email before proceeding or decliningAny charge over $200
BlockRedHard stop, log reason, notify userElectronics category always blocked

Available Conditions

  • Agent — specific agent, or any agent
  • Card alias — specific card or any card
  • Merchant category (MCC) — groceries, electronics, travel, SaaS, etc.
  • Amount — under/over absolute value, or exceeds budget by X%
  • Time of day / day of week — (V2) no spending after midnight
  • Velocity — (V2) max N transactions per time period

Policy Evaluation Order

Policies are evaluated top-to-bottom. First match wins. This is the same model as firewall rules — familiar to any developer or IT person.

Important implementation note

Start with deterministic JSON-based rules — no AI in the loop for V1. Sub-50ms evaluation is critical. Add LLM semantic checking later (V3) only for escalation decisions, not the happy path.


Architecture

Five Core Components

1. MCP Server (the entry point)

TypeScript/Node.js service that exposes the same tools as the payment MCP it wraps. Runs on localhost:4242. Agent calls it thinking it's talking to Stripe. Troxy receives, enriches with context, evaluates, then forwards or blocks.

2. Policy Engine (the brain)

Pure evaluation service. Receives a transaction request, returns ALLOW, BLOCK, or ESCALATE. V1: deterministic JSON rules, sub-50ms. V3: LLM semantic intent check for escalations. Tech: Lambda + DynamoDB for rule storage.

3. Budget Envelope Service

Stateful real-time tracking of spending against budgets. Must be fast and consistent — no race conditions. Tech: Redis (ElastiCache) for atomic real-time state. DynamoDB as persistent source of truth. EventBridge for scheduled resets.

4. Notification + Approval Flow

When ESCALATE: transaction held, user notified via SNS (push/email/Slack), signed approval token generated. User taps approve → webhook releases transaction. Configurable timeout: no response = auto-decline. WebSocket for real-time dashboard updates.

5. Audit + Event Store

Every event logged — transactions, evaluations, escalations, approvals, blocks. Full context: agent, task, card, policy that triggered. Tech: Postgres RDS for structured queries + S3 for raw event archival. EventBridge as the event bus.

AWS Infrastructure

Route53 (DNS)
    ↓
CloudFront (CDN + DDoS)
    ↓
API Gateway
    ↓
Lambda — MCP Server
Lambda — Policy Engine          DynamoDB (policies, rules)
Lambda — Approval Handler   →   ElastiCache Redis (envelopes)
Lambda — Audit Logger           RDS Postgres (audit trail)
    ↓                           S3 (event archive)
EventBridge (event bus)
SNS (push notifications)
SES (email)

URL Structure

SubdomainPurposeHosting
troxy.aiMarketing siteS3 + CloudFront
dashboard.troxy.aiUser consoleS3 + CloudFront
install.troxy.aiInstall shell scriptS3 + CloudFront
releases.troxy.aiDaemon binaries by versionS3 + CloudFront
api.troxy.aiBackend REST APIAWS Lambda + API Gateway
status.troxy.aiUptime status pageStatuspage.io

Early Stage Cost Estimate

ServiceMonthly cost
S3 + CloudFront (binaries + install script)~$5
Lambda (scales to zero)~$0 early stage
RDS Postgres (t3.micro)~$20
ElastiCache Redis (t3.micro)~$15
S3 + CloudFront (frontend)~$0 (free at MVP scale)
Total early stage~$40–50/month

MVP Product Scope
Exactly what the MVP does and what it does not. This is the complete product for the investor demo. Nothing more gets built until we have real user feedback telling us what to build next.
The MVP principle

A user installs Troxy in 2 minutes, connects their agent, sets a few rules, and from that moment — every payment their agent tries to make goes through Troxy first. They see it all in the dashboard. They approve or block from their email. That's the whole product. Simple, complete, demonstrable.

What a user can do with the MVP — the complete list

Feature What the user actually does In MVP
Install Run npx troxy init, paste API token, done. Daemon starts and auto-connects to Claude Desktop / Cursor. No config beyond the token. ✅ Yes
Add a card alias Give a card a nickname ("Gilad's Groceries"), enter last 4 digits, set an optional monthly budget. The real card number is never stored — Troxy only needs the alias to track spending and apply policies. ✅ Yes
Create a policy rule Pick a condition (category = electronics, amount > $200, etc.) and an action (ALLOW / BLOCK / ESCALATE). Give it a priority. Rules evaluate top-to-bottom, first match wins. User can have 10+ rules. ✅ Yes
Set a monthly budget Attach a monthly spending limit to any card alias. When the agent tries to spend beyond it, Troxy automatically escalates instead of allowing. Budget resets on the 1st of each month. ✅ Yes
See the activity log Dashboard shows every transaction attempt — allowed, blocked, or escalated — with the merchant name, amount, which policy fired, and the timestamp. Immutable, append-only. Exportable later. ✅ Yes
Approve or decline from email When a transaction is escalated, user gets an email with the merchant, amount, and reason. Two buttons: Approve or Decline. One click. Expires in 10 minutes. If expired, request is automatically declined. ✅ Yes
See budget usage Dashboard overview shows each card alias with a progress bar: how much of the monthly budget has been used and how much remains. ✅ Yes
Revoke a token If a machine is lost or compromised, user revokes the token from the dashboard. The daemon on that machine stops processing all calls immediately. ✅ Yes
Register an agent Give each agent a name (e.g. "Shopping Agent", "Travel Agent"). Policies can target a specific agent or apply to all agents. For MVP: one agent per user is fine. ✅ Yes

The 5-minute user journey — from install to first blocked payment

Minute 0: Run: npx troxy init
           → Binary downloads, daemon starts
           → Browser opens dashboard.troxy.ai/connect

Minute 1: Sign up with email
           → Create API token ("My MacBook")
           → Paste token in terminal → "✅ Connected"

Minute 2: Add a card alias
           → Name: "Main Card", Last 4: 1234, Budget: $500/mo
           → Click save

Minute 3: Create a policy
           → "Block Electronics" — category: electronics → BLOCK
           → Priority 10, save

Minute 4: Open Claude Desktop
           → Ask: "buy me AirPods Pro for $249"
           → Claude gets blocked ❌
           → Dashboard shows the block with reason

Minute 5: Ask: "book a hotel for $350" (budget $500)
           → Escalated — email arrives in seconds
           → Click Approve ✅
           → Dashboard shows approved

→ Troxy is working. The agent is under control.

What is NOT in the MVP — and why

Feature Why it waits When
Insights / analytics tab Needs real spending history to be useful. With 10 test users we have no data. Build after launch when users ask for it. V2
Claude API intent verification Deterministic rules cover 95% of cases. LLM intent check is a nice-to-have, not a blocker for the demo. Adds cost and latency before we need it. V2
Smart card routing Auto-selecting the right card based on merchant category. Cool feature, not core to the value prop. Manual alias selection in policies is enough for MVP. V2
Slack / push notifications Email is sufficient for MVP approval flow. Slack adds integration complexity. Add when users ask for it. V2
Multi-user / teams MVP is single user. Team features (shared policies, multiple approvers, role-based access) require a lot of UX and auth work. Post-funding. V3
Mobile app Email approval flow works fine for MVP. Native app is post-funding, post-PMF. V3
Subscription / billing MVP is free. We're not charging anyone yet — we're proving the product works. Add paid plans after first 100 real users. V2
Multiple MCP servers MVP intercepts Stripe MCP only. Adding PayPal, Shopify, etc. is straightforward but not needed to prove the concept. Start with Stripe — most developer agents use it. V2
Anomaly detection Needs a baseline of real spending data to detect anomalies. Not possible at MVP with 10 users. Build when we have real transaction history. V3

Dashboard pages — MVP only

The dashboard has 5 pages in MVP. Insights is included but shows only simple data-driven metrics — no AI, no Claude API. That's V2.

Page What it shows In MVP
Overview Budget bars per card alias (used vs remaining), daemon status (online/offline), last 5 transactions at a glance ✅ Full
Policies List of all policy rules ordered by priority, create/edit/delete/reorder. Toggle enable/disable per rule. ✅ Full
Activity Full transaction log — every ALLOW, BLOCK, ESCALATE with merchant, amount, policy matched, timestamp. Filterable by decision type. ✅ Full
Cards Card aliases with their budgets and current usage. Add/edit/delete aliases. Budget reset date visible. ✅ Full
Insights Simple data-driven metrics from the audit_log — no Claude API needed. See below for exact scope. ✅ V1 (SQL only)

Insights V1 — what's in MVP (pure SQL, no AI)

Everything below is a simple query on the audit_log table. No Claude API, no ML, no external services. One afternoon of work. Shows investors real data without overbuilding.

Metric How it's built
Total spent this monthSUM(amount) WHERE decision='ALLOW' AND month=current
Decisions breakdownCOUNT(*) GROUP BY decision — pie chart: X allowed, Y blocked, Z escalated
Top 5 merchants by spendGROUP BY merchant_name ORDER BY SUM(amount) DESC LIMIT 5
Spend by categoryGROUP BY merchant_category — bar chart per category
Budget health per cardProgress bar: used vs limit — same data as Overview but more detail
Spend over timeGROUP BY date_trunc('day', created_at) — simple line chart, last 30 days

Insights V2 — post-MVP technical implementation

Build when we have 50+ active users with real spending history. The technical approach is simple — one Lambda, one Claude API call, results cached in RDS. No new infrastructure needed beyond what MVP already has.

How it works in one sentence

A Lambda queries the user's audit_log, formats the data as context, sends it to the Claude API, gets back a plain-language analysis, caches it in RDS, and the dashboard displays it. That's it.

The flow

# User clicks "Generate Insights" in dashboard

1. Dashboard calls: POST /dashboard/insights/generate

2. insights-generator Lambda runs:
   a. Query audit_log — last 30 days of transactions for this user
   b. Aggregate: totals, categories, merchants, trends
   c. Build Claude API prompt (see below)
   d. Call Claude API → claude-sonnet-4
   e. Parse response → structured JSON
   f. Cache result in RDS (insights_cache table, expires 24h)
   g. Return to dashboard

3. Dashboard displays the insights

# On subsequent loads within 24h → serve from RDS cache
# No Claude API call = no cost
# User can force-refresh: DELETE /dashboard/insights/cache

The Claude API prompt — exactly what we send

// System prompt
You are a financial insights assistant for Troxy, an AI agent payment control layer.
Analyze the user's agent spending data and return a JSON object with insights.
Be concise, specific, and actionable. Never invent data not in the input.
Respond ONLY with valid JSON — no preamble, no markdown.

// User prompt (built dynamically from audit_log data)
Here is the user's agent spending data for the last 30 days:

Total spent: $1,247.50
Total blocked: $340.00 (12 transactions)
Total escalated: $490.00 (5 transactions, 4 approved, 1 declined)

Transactions by category:
- grocery: $342.00 across 8 transactions (merchants: Rami Levy x5, Shufersal x3)
- travel: $480.00 across 3 transactions (merchants: Marriott x2, Booking x1)
- software: $199.00 across 1 transaction (merchants: Ahrefs x1)

Blocked transactions:
- electronics: $249.00 (AirPods Pro) — blocked by "Block Electronics" policy
- electronics: $91.00 (phone case) — blocked by "Block Electronics" policy

Recurring charges (same merchant, multiple months):
- Ahrefs: $199.00 in March, $199.00 in February, $199.00 in January

Return this JSON structure:
{
  "summary": "2-3 sentence plain-language overview of this month's spending",
  "highlights": ["up to 3 short bullet points — notable patterns or facts"],
  "duplicates": [
    { "merchant": "name", "amount": 199.00, "months": 3, "note": "recurring monthly" }
  ],
  "anomalies": [
    { "description": "what's unusual", "severity": "low|medium|high" }
  ],
  "suggestions": [
    { "text": "actionable suggestion", "potential_saving": 50.00 }
  ]
}

Example Claude API response

{
  "summary": "Your agents spent $1,247 this month, with travel being the largest category at $480. Troxy blocked $340 in electronics purchases and escalated 5 transactions for your approval, of which you approved 4.",
  "highlights": [
    "Travel spending is up — 3 hotel charges totaling $480 in 30 days",
    "Ahrefs subscription recurring at $199/mo for 3 consecutive months",
    "All blocked transactions were electronics — your policy is working"
  ],
  "duplicates": [
    {
      "merchant": "Ahrefs",
      "amount": 199.00,
      "months": 3,
      "note": "Recurring monthly subscription — consider reviewing if still needed"
    }
  ],
  "anomalies": [
    {
      "description": "Travel spend this month ($480) is 3x higher than the previous 2-month average ($160)",
      "severity": "medium"
    }
  ],
  "suggestions": [
    {
      "text": "You have no spending limit on the travel category. Consider adding a monthly travel budget to avoid surprise escalations.",
      "potential_saving": null
    },
    {
      "text": "Ahrefs has been charged 3 months in a row. Verify this subscription is still actively used.",
      "potential_saving": 199.00
    }
  ]
}

New database table — insights_cache

-- Add to existing schema when building V2
insights_cache (
  id          UUID PRIMARY KEY,
  user_id     UUID REFERENCES users(id),
  period_days INTEGER NOT NULL,     -- 30 | 90
  result      JSONB NOT NULL,       -- full Claude API response
  tokens_used INTEGER,              -- track API cost
  created_at  TIMESTAMPTZ DEFAULT now(),
  expires_at  TIMESTAMPTZ NOT NULL  -- now() + 24h
)

New API endpoints for V2

# Generate (or serve from cache)
POST /dashboard/insights/generate?period=30d
→ Returns insights JSON (from cache if fresh, from Claude if stale)
→ Cost: ~$0.01–0.05 per call (Sonnet 4 pricing at ~2K tokens input)

# Force refresh — bypass cache
POST /dashboard/insights/generate?period=30d&refresh=true

# AWS service: same core-handler Lambda, new route
# No new Lambda needed — just a new function in core-handler
# Secrets Manager: add troxy/anthropic/api_key

New secret needed

Secret nameWhat it containsUsed by
troxy/anthropic/api_keyAnthropic API key for Claude callscore-handler Lambda (Insights V2 route only)

Cost per user per month

ScenarioAPI calls/moCost per user
User generates insights once/week~4 calls (cache handles the rest)~$0.10–0.20/mo
User generates daily~30 calls~$0.60–1.50/mo
100 active users, weekly usage~400 calls total~$15–20/mo total — completely manageable
Why the cache matters

Without caching, every dashboard page load would call Claude API — that would be expensive and slow. With the 24-hour cache, we call Claude at most once per user per day. Most users check insights a few times a week. Real cost at 100 users: under $20/month total. Covered comfortably by any paid plan.

What's needed to build V2 — checklist

TaskEffort
Add insights_cache table to RDS (migration)30 min
Add troxy/anthropic/api_key to Secrets Manager10 min
Add Insights V2 route to core-handler Lambda1 day
Update Insights page in dashboard to show AI content1 day
Apply for Anthropic for Startups credits10 min — do before building
Total~2–3 days of work

The "agent" clarification — important

Troxy does not have its own agent

The word "agent" in this document always refers to the external AI that the user is already running — Claude Desktop, Cursor, a custom script, etc. Troxy is the proxy layer that intercepts calls from that external agent. We don't deploy an agent. We don't build an agent. The user brings their own agent — we just sit in the middle and control what it can spend.

User's external agent (Claude Desktop, Cursor, custom)
              ↓  makes MCP payment tool call
         Troxy daemon (localhost:4242)     ← we build this
              ↓  evaluates against policies
         Troxy API (api.troxy.ai)          ← we build this
              ↓  ALLOW → forwards to real MCP server
         Real payment provider (Stripe MCP)
              ↓
         Actual payment

# The only place Claude API enters Troxy is Insights V2
# — a Lambda calling Claude to generate plain-language summaries.
# That's just an API call. Not an agent. Not something to deploy.
# Leave it for post-MVP.
Is this enough for investors?

Yes — because it proves the hardest thing: Troxy is genuinely in the middle of the agent's payment calls. The agent tries to spend, Troxy intercepts, decides, and either allows, blocks, or escalates. The dashboard shows real data. The Insights tab shows real metrics. Investors don't fund feature lists — they fund proof that the core mechanism works and that someone will pay for it. This is enough.


Installation & Distribution

The One-Line Install

The magic moment

The install IS the acquisition. One command, everything configured, dashboard live. This is the moment someone decides to use Troxy.

npx troxy init

What Happens During Install

✓ Detecting installed agent tools (Claude Desktop, Cursor...)
✓ Found Claude Desktop config at ~/Library/Application Support/Claude/
✓ Found Cursor config at ~/.cursor/mcp.json
✓ Backing up original configs
✓ Injecting Troxy proxy for: stripe, paypal, shopify
✓ Starting Troxy daemon on localhost:4242
→ Opening browser → dashboard.troxy.ai to finish setup
✓ Done. All agent payments now route through Troxy.

Install Per Platform

PlatformCommandBackground servicePriority
Macbrew install troxy or curl | shlaunchd plistFirst
Dockerdocker run troxy/daemonContainer restart policyFirst
Linuxcurl | sh or apt/yumsystemd serviceSecond
Windowswinget install troxyWindows ServiceThird
npx (universal)npx troxy initSession onlyFirst (try)

Docker — The Enterprise Play

Companies running internal agents don't run them on someone's MacBook. They run them on EC2, Kubernetes, or GitHub Actions. Docker is their natural answer.

# docker-compose.yml
version: '3'
services:
  troxy:
    image: troxy/daemon:latest
    environment:
      - TROXY_TOKEN=${TROXY_TOKEN}
      - TROXY_POLICY=strict
    ports:
      - "4242:4242"
    restart: always

  my-agent:
    image: my-company/procurement-agent
    environment:
      - MCP_STRIPE_URL=http://troxy:4242/stripe
    depends_on:
      - troxy

API Tokens

The daemon requires an API token to function. No token = daemon doesn't start. This is the gate between a free install and an account.

Signup flow

  1. User runs npx troxy init
  2. Terminal prompts: create account or paste token
  3. Browser opens to troxy.ai/signup — 30 seconds, Google OAuth
  4. Token generated: txy-xk29dj8f...
  5. User pastes back in terminal
  6. Daemon starts, machine appears as "Online" in dashboard
  7. User asks Claude to do something with money — first transaction appears
  8. Aha moment.

Multiple Tokens

One account, many tokens — one per machine, environment, or use case. Each token can be revoked individually without affecting others. Model: identical to GitHub personal access tokens or AWS access keys.

Why Go for the Daemon Binary

The daemon should be written in Go. Single reason: compiles to one static binary per OS with zero dependencies. No runtime required.

GOOS=darwin  GOARCH=amd64 go build -o troxy-mac
GOOS=darwin  GOARCH=arm64 go build -o troxy-mac-m1
GOOS=linux   GOARCH=amd64 go build -o troxy-linux
GOOS=windows GOARCH=amd64 go build -o troxy.exe

Backend & Hosting

The Distribution Chain

User runs: npx troxy init
                ↓
    Hits: install.troxy.ai (shell script on S3)
                ↓
    Script detects OS → downloads binary from:
    releases.troxy.ai/v1.0.2/troxy-mac
                ↓
    Daemon starts → connects to:
    api.troxy.ai
                ↓
    Fetches policies, logs traffic, sends notifications

Three Servers, Three Jobs

install.troxy.ai — The install script

50-line bash script hosted on S3 + CloudFront. Detects OS, downloads right binary, sets up background service. Globally cached, costs pennies. Same pattern as Homebrew, Rust, ngrok installers.

releases.troxy.ai — Binary store

Versioned directory of compiled daemon binaries on S3. Every release publishes all platform variants. Also consider GitHub Releases early on — free, built-in versioning, zero ops.

api.troxy.ai — The brain

The real backend. AWS Lambda + API Gateway + RDS + Redis. This is where policies live, events are logged, approvals are managed. Full infra as Terraform — you know this pattern from Rapyd.

Daemon ↔ Cloud Communication

Policies are cached locally on the machine for fast evaluation. No network round trip on every transaction:

  1. On startup: daemon calls api.troxy.ai/v1/policies → fetches user's rules → caches locally
  2. Every transaction: evaluated against local cache — no network needed
  3. After decision: event logged to api.troxy.ai/v1/events asynchronously
  4. Cache refreshes every few minutes from cloud
Resilience benefit

This means Troxy keeps working even if the internet is slow or the API is temporarily down. Local cache + async logging = no single point of failure for the core enforcement function.


Security

What Troxy Sees vs. What It Never Sees

Troxy DOES see
  • Transaction amount
  • Merchant name
  • Merchant category
  • Which agent made the request
  • Timestamp
  • Task context
Troxy NEVER sees
  • Full card number
  • CVV
  • Card expiry
  • Bank account details
  • User passwords
  • Raw MCP payloads
The key statement for enterprise sales

"Troxy never processes, stores, or transmits card numbers or payment credentials. We are a decision layer, not a payment processor. Card credentials go directly between your payment provider and the merchant."

Five Security Pillars

1. Never touch card data (architectural)

Troxy routes the decision, not the money. The actual payment credentials never enter Troxy's systems. Get this verified by a security auditor and put it on the trust page explicitly.

2. Encryption everywhere

At rest: AWS KMS encrypts RDS, S3, DynamoDB. API tokens stored as bcrypt hashes only. In transit: TLS 1.3 minimum. Daemon ↔ API uses mTLS (mutual TLS) — both sides verify certificates. HSTS on all web properties. Certificate pinning in daemon binary.

3. Data minimization

Only log what's needed: amount, merchant, category, agent ID, decision, policy applied. Never log full MCP payloads or card details. 90-day retention default, then deleted. Enterprise can configure longer.

4. Local-first evaluation

Policy decisions happen on the user's machine against a local cache. For 99% of transactions, nothing leaves the machine except an async audit log. This is both a security and performance win.

5. Token security

Never log tokens. Store only bcrypt hashes. Tokens expire and are rotatable from dashboard. One-click revoke per machine. Rate limit all API endpoints. Anomaly detection: token used from new country/IP → alert user immediately.

Compliance Roadmap

CertificationWhy it mattersWhen
SOC 2 Type IIEnterprise sales requirement — without this, Fortune 500 cannot signAs soon as first paying customers
GDPREuropean users — DPA template, right to deletion, EU data residencyDay 1 — write the policy
PCI DSS scope letterQSA confirms Troxy is out of scope — not a card processorBefore first enterprise deal
ISO 27001Enterprise nice-to-haveAfter SOC 2

The Trust Page

troxy.ai/security — publish this from day one. It does more for enterprise sales than any pitch deck slide. Should contain: architecture diagram showing no card data, encryption standards, SOC 2 report when available, pen test results, bug bounty program, incident response SLA, uptime status link, contact: [email protected].


How We Actually Enforce

This is the most critical technical question: how do we guarantee agents can't bypass Troxy? A config file rewrite is a gentleman's agreement — not a technical guarantee. Here are the three enforcement levels:

LevelMethodGuaranteeWhen to build
1MCP config rewriteLow — well-behaved agents onlyV1 (already described)
2DNS interception + firewall rulesHigh — blocks direct endpoint accessV1 — build this
3Full TUN/VPN interfaceVery high — all trafficV2 enterprise
4Cryptographic payment provider tokensAbsoluteV4 — requires partnerships

Level 2 — DNS Interception (Recommended for V1)

Troxy runs a local DNS resolver that intercepts requests to payment domains:

# Agent resolves: mcp.stripe.com
# Normal DNS:   → 54.187.x.x (Stripe's real IP)
# Troxy DNS:    → 127.0.0.1 (localhost, Troxy)

# Agent thinks it's talking to Stripe.
# It's actually talking to Troxy.
# Troxy forwards if policy allows.

Level 2 — Firewall Rules

# Mac pf firewall — blocks direct access to payment endpoints
block out proto tcp to mcp.stripe.com port 443
block out proto tcp to mcp.paypal.com port 443
# Only allow through Troxy
pass out proto tcp from localhost:4242 to mcp.stripe.com port 443
Dashboard feature idea

Show a "Security Status" panel in the dashboard: which enforcement layers are active, and a counter for "bypass attempts blocked." The moment a user sees their agent tried to go around Troxy and was caught — they will never uninstall it.


Market
Agentic AI market by 2034
$199B
44% CAGR
US agent commerce by 2030
$1T
B2C alone
Execs expecting mainstream in 3 yrs
57%
Accenture 2025
Consumers who trust AI to pay autonomously
16%
The fear is real

TAM / SAM / SOM

LevelDefinitionSize
TAMAll agentic commerce payment infrastructure~$10B by 2030
SAMDeveloper & SMB agent payment tooling~$1.5B by 2028
SOMMCP-native auth layer, Year 1-3~$150M

Competitive Landscape

CompetitorWhat they doThe gap
Visa Intelligent CommerceNetwork identity + tokenization for enterprise partnersNo developer self-serve, months to onboard
Mastercard Agent PayAgentic tokens for large issuersSame gap as Visa
Ramp Agent CardsCorporate spend management with agent cardsEnterprise only, no task context
Stripe IssuingCard infrastructure for merchantsMerchant-facing, not agent-facing
CardForAgent.comInstant prepaid card via MCPNo policy layer, no task context, no audit
TroxyTask-aware policy enforcement, envelopes, routing, auditThe gap nobody fills

Four Customer Segments

1. The Business Owner

Given AI assistant access to company cards. Needs budget control and visibility without manual oversight. Buyer: founder or CFO of 10–200 person company.

2. The Developer Building Agent Products

Building a product where users need agents that can transact. Can't hand users a raw credit card. Needs Troxy's MCP as drop-in safety layer. Buyer: developer, integrates via SDK.

3. The Finance Team at Scaling Company

Teams deploying internal agents 24/7. Procurement bots, travel agents, vendor payment automation. Need audit trail and policy enforcement. Buyer: CFO or CISO.

4. Individual with Peace of Mind

Uses Claude or ChatGPT for daily tasks. Wants to feel safe giving agent access to cards. Free tier user, possible bottom-up enterprise motion. Buyer: consumer.


Business Model

Revenue Streams

Policy Layer SaaS
$49–$499/mo

Tiered subscription for SMBs. Includes advanced policy rules, multi-agent support, approval workflows, audit exports.

Enterprise API
Custom

White-labeled authorization engine. Revenue share + flat licensing. SOC 2, dedicated support, SLA.

Developer Free Tier
$0

500 transactions/month. Bottom-up acquisition — developers bring Troxy to their companies.

Unit Economics (SMB)

MetricValue
SMB ARPU$180/month
Average agent spend managed$3,200/month
Gross margin>75%
Target 18-month: paying SMBs300
Target 18-month: ARR~$650K

Pricing Tiers — Freemium Model (Freemius-style)

Free forever for 1 person, 1 machine, 1 card. Pay to scale. Bottom-up: individual dev uses free → brings it to their company → company upgrades.

FeatureFreePro ($29/mo)Enterprise
MCP connections (API keys)1UnlimitedUnlimited
Cards1UnlimitedUnlimited
Policies3UnlimitedUnlimited
Transactions/mo500UnlimitedUnlimited
Team members (users)1Unlimited
Named MCP connections✓ (distinguish agents)
Approval flow
Audit export
SSO / SAML
SLA + dedicated support

Technical Readiness for Freemium

CapabilityStatusNotes
Multiple named API keys (MCPs)DoneAlready in DB + dashboard. Free limit = 1, enforce at creation.
Multiple cardsDoneAlready works. Free limit = 1, enforce at creation.
Multiple policiesDoneAlready works. Free limit = 3 suggested.
plan field on users (free/pro)EasyOne DB migration + check at resource creation endpoints.
Limit enforcement at APIEasyCount rows before INSERT in cards.py / tokens.py, return 403 if over limit.
Upgrade flow / StripeMediumStripe Checkout + webhook to flip user.plan. ~1 week.
Team / multi-user accountsHardRequires organizations table, org_members, re-scoping all resources from user_id → org_id. Design needed before building.

Go-to-Market

Phase 1 — Developer Land Grab (Months 1–6)

  • Ship MCP server + API, free tier: 500 transactions/month
  • Post on Hacker News (Show HN), ProductHunt, r/ClaudeAI, r/LangChain
  • Write tutorials: "How to add spending controls to your Claude agent in 5 minutes"
  • Integrate with Claude Desktop, Cursor, Windsurf
  • Target: 2,000 active developers

Phase 2 — SMB Conversion (Months 6–18)

  • Paid policy layer ($49–$499/month)
  • Multi-agent support, approval workflows, finance team dashboard
  • Bottom-up motion: developer uses free tier → brings to company → company pays
  • Target: 300 paying SMBs

Phase 3 — Platform Partnerships (Year 2–3)

  • Partner with AI platforms — be the default payment safety layer
  • White-label enterprise deals
  • Visa/Mastercard ecosystem program — cryptographic token integration
  • Target: 3 platform deals

Validation Approach — Before Writing Code

DayActionOwner
1–2Build landing page, clear problem/solution statement, waitlist CTABoth
3Post on HN, relevant communitiesBoth
3–4Yuval sends 20 messages to HBS network — "how are you handling agent payment risk?"Yuval
4–5Gilad has informal conversations at Rapyd — would they buy this?Gilad
5–75–10 customer discovery calls with people who respondBoth
Validation signals to look for

"I already tried to solve this myself" — strongest signal. "Who do I pay and when can I get it" — even stronger. "I know five other people with this problem" — means you're not in a niche of one.


MVP Roadmap & Status

Last updated: April 2026. Focus: 100% test before going live, then enforce plan limits.

Pre-Launch: Test Everything

ItemStatusNotes
ALLOW flow end-to-endDoneTransactions show in dashboard, budget_used updates
BLOCK flowTo testCreate a block policy, trigger via MCP, verify 0 budget impact
NOTIFY flowTo testPolicy action exists, SNS wiring needs verification
ESCALATE flowTo testBlocked on SES production access for approval email
MCP green dotDoneHeartbeat → Lambda → dashboard polls every 30s
Dashboard overviewDoneStats, recent activity, budget envelopes all loading
Responsive dashboardDoneHamburger menu on mobile
CLI init/login/mcp flowDoneTested on EC2. Version 0.1.9 on npm.
Automate npm publishTo doAdd GitHub Action with NPM_TOKEN secret — no more manual OTP
SES production accessTo doSubmit AWS request. Blocker for real user signups + ESCALATE emails
Budget monthly resetBugbudget_reset_day column exists but no cron job zeros out budget_used. Cards accumulate forever.

Pre-Monetization: Plan Enforcement

ItemEffortNotes
Add plan field to users (free/pro)EasyOne DB migration
Enforce 1 card / 1 API key on free tierEasyCount rows before INSERT, return 403 with upgrade message
Show upgrade prompt in dashboardEasyBanner/modal when hitting free tier limits
Stripe checkout + webhookMedium~1 week. Webhook flips user.plan to pro.
Team / multi-user accountsHardRequires org model refactor. Enterprise tier only — defer until needed.

Known Bugs

BugImpactFix
Budget never resets monthlyHigh — cards show wrong spend foreverEventBridge cron → Lambda → reset budget_used WHERE budget_reset_day matches day
Lambda migration lock_timeout was session-levelFixed Apr 2026Changed to SET LOCAL — reverts on commit
pg_advisory_lock deadlock on cold startFixed Apr 2026Removed advisory lock entirely

The Founding Team

Gilad

Role: CTO / Technical Co-founder

  • DevSecOps / Network Engineer at Rapyd (payment company)
  • AWS CloudWAN, multi-account architecture, security infrastructure
  • Terraform, Terragrunt, ControlMonkey — IaC daily
  • Lives the buyer problem — would evaluate and buy this tool
  • Rapyd as potential first reference customer

Yuval Kadmon

Role: CEO / Business Co-founder

  • MBA Candidate, Harvard Business School
  • McKinsey & Company — enterprise financial workflows
  • Lieutenant, Israeli Navy — 7.5 years
  • HBS network for fundraising and enterprise distribution
  • Built automated Python pipelines — understands agentic tooling
Why this team

Yuval brings enterprise GTM and fundraising credibility. Gilad brings technical depth and the "I lived this problem at a payment company" founder story. Together: the suit in the room + the engineer who'd actually build and use the product. That combination is rare and valuable.

Equity Structure Note

50/50 agreed. Recommendation: consider 51/49 with clear domain ownership to avoid deadlocks under pressure — Yuval owns business/GTM decisions, Gilad owns product/technical decisions. Have this conversation before lawyers and cap tables.

Seed Round Target

Use of fundsAllocation
Engineering (MCP server, policy engine)40%
BaaS integration + infrastructure30%
Developer growth + community20%
Legal, compliance, operations10%
Total target$2.5M

Build Order & Checklist
The exact sequence to build Troxy MVP. Never move to the next step until the current one passes its test. Each step has a clear pass/fail condition — no ambiguity about whether you're done.
The rule

One step at a time. One Claude Code task at a time. Test passes → next step. Test fails → fix before moving on. Never skip ahead.

How to use this with Claude Code

# For each step, give Claude Code exactly this:

"Build [step name].
Here is the spec: [paste relevant sections]
Rules:
- Everything in Terraform + Terragrunt
- No manual AWS console steps
- Follow the spec exactly, nothing extra
- Use us-east-1"

# Never give Claude Code the whole document at once
# Never ask it to build more than one step at a time
# Always review the output before committing

Phase 1 — Infrastructure

Goal: AWS is fully provisioned by Terraform. CI/CD pipeline live. No manual AWS console clicks.

# Step Spec sections ✅ Pass condition
1OIDC GitHub → AWS trustSection 17, 18Push to troxy-tf-live → GitHub Actions runs → authenticates with AWS → no errors
2S3 + CloudFront (dashboard hosting)Dashboard Deploy sectioncurl https://dashboard.troxy.io → returns something, even a blank page
3RDS PostgreSQLSection 19Connect from local via SSO credentials → psql works → can create tables
4Secrets ManagerSection 29 — Error Handlingaws secretsmanager get-secret-value --secret-id troxy/rds/password → returns value
5SES domain verificationSection 18SES console shows troxy.io as Verified → send test email → lands in inbox not spam

Phase 2 — Backend

Goal: /evaluate endpoint works end to end. ALLOW and BLOCK paths fully functional.

# Step Spec sections ✅ Pass condition
6Database schema + migrationsSection 19psql → \dt → shows all 8 tables
7core-handler Lambda (ALLOW + BLOCK)Section 25, 27, 28POST /evaluate with valid token → returns ALLOW → audit_log row created in RDS. Same with BLOCK policy → returns BLOCK.
8API GatewaySection 25curl https://api.troxy.io/health → returns {"status":"ok"}

Phase 3 — Approval Flow

Goal: Full ESCALATE path works. Email arrives, approve/decline links work, RDS updated.

# Step Spec sections ✅ Pass condition
9approval-webhook LambdaSection 25, 28, 29POST /evaluate → returns ESCALATE → email arrives in inbox → click Approve → pending_approvals updated in RDS → click Decline → same
10Full backend validationSection 22Run all validation checklist items from Section 22 — all pass → backend is done

Phase 4 — Dashboard

Goal: Real UI connected to real data. No hardcoded mock data anywhere.

# Step Spec sections ✅ Pass condition
11Auth flow (magic link)Section 30 — Auth & SAMLGo to dashboard.troxy.io → enter email → magic link email arrives → click → logged in → JWT in browser
12Dashboard 5 pagesSection 11, 34Each page loads real data from api.troxy.io — Overview, Policies, Activity, Cards, Insights V1
13GitHub Actions deploy pipelineDashboard Deploy sectionPush to main → GitHub Actions runs → dashboard.troxy.io updates in under 2 minutes

Phase 5 — Daemon

Goal: Claude Desktop intercepted. Agent payments flow through Troxy.

# Step Spec sections ✅ Pass condition
14Go daemon — install + startSection 26, 32npx troxy init → installs binary → troxy daemon status → running → curl localhost:4242/health → ok
15MCP config rewrite + interceptionSection 27, 33Open Claude Desktop → ask agent to make a payment → Troxy intercepts → decision appears in Activity tab 🎉

Phase 6 — Demo Ready

The final test — all 9 steps must pass

This is what you show investors. Run through it exactly as written. If any step fails — fix it before showing anyone.

Step 1: npx troxy init
        → installs, daemon starts, Claude Desktop connected       ✅

Step 2: Open dashboard.troxy.io
        → loads clean, real data, no errors                       ✅

Step 3: Add card alias + $500 monthly budget
        → saves to RDS, appears in Cards tab                      ✅

Step 4: Create "Block Electronics" policy
        → saves to RDS, appears in Policies tab                   ✅

Step 5: Open Claude Desktop, connect agent
        → daemon shows machine as Online in dashboard             ✅

Step 6: Ask agent: "buy AirPods Pro for $249"
        → Troxy intercepts → BLOCK
        → Activity tab shows block with reason                    ✅

Step 7: Ask agent: "book a hotel for $350"
        → Troxy intercepts → ESCALATE
        → Approval email arrives in inbox within 10 seconds       ✅

Step 8: Click Approve in email
        → payment goes through
        → Activity tab shows ESCALATE → Approved                  ✅

Step 9: Ask agent: "buy groceries for $30"
        → Troxy intercepts → ALLOW
        → Activity tab shows ALLOW                                ✅

All 9 pass → you're ready for investors. 🚀

What Gilad builds, what Yuval does — in parallel

Gilad — Technical
  • All 15 build steps above
  • Go daemon + MCP interception
  • Review every Claude Code output before committing
  • Keep the internal doc updated as decisions change
Yuval — Business
  • 20 customer discovery calls
  • Waitlist page live on troxy.io from day 1
  • AWS Activate + Anthropic for Startups credits
  • Stripe Atlas — legal entity
  • Investor list + warm intro outreach
  • First 5 investor meetings booked by demo day

More Ideas
Everything we brainstormed — near-term features, wild future bets, and things that could make Troxy genuinely category-defining. Some of these are V2, some are V5, some might become the whole company.

Things We Talked About — To Build

Credit card treated as debit card

The envelope feature we discussed — user loads a virtual budget onto any credit card. Agent can only spend up to that amount. When it runs out, blocked. Feels like a prepaid card psychologically, credit card behind the hood. This was one of the original vision ideas and it's a headline feature.

Notify before declining (% over budget)

If agent tries to spend more than X% over the envelope, send push notification before auto-declining. User has a configurable window to approve. This is the feature that turns Troxy from a rigid blocker into a smart assistant. Already in V1 plan — build this first.

Multi-card smart routing

Business Amex for work expenses, personal Visa for groceries, Romi's Mastercard for her agent only. Troxy automatically routes to the right card based on merchant category, agent identity, and user-defined rules. No more wrong card on the expense report.

Family plan / sub-users

Give Romi her own Troxy login with limited permissions. She can see her agent's activity, her card's budget, but nothing else. Parent/guardian controls their children's AI agent spending. This is actually a massive consumer opportunity nobody has touched.

Product Features — Near Term

Receipt per transaction

Every approved transaction generates a structured receipt — merchant, amount, agent, task context, policy that approved it, timestamp. Exportable. Accountants will love this. Finance teams will demand it.

Monthly spend digest email

Auto-generated email on the 1st of every month. "Your agents spent $X last month. Here's what they bought, which agent spent what, and what was blocked." Clean summary, no login required to read it.

Velocity rules

Max 3 transactions per hour. Max $500 in any 24-hour window. Catches agents that loop or hallucinate and try to place the same order 200 times. This is the hallucination risk defense layer.

Time-based policies

No agent spending between midnight and 6am. Weekend spending requires approval. Holiday lockdown mode. Useful for companies that want to ensure no autonomous spending happens outside business hours.

Merchant allowlist / blocklist

Whitelist specific merchants your agent can always use. Blacklist others it can never touch. "My travel agent can always book Marriott and Delta. It can never buy from Amazon." Simple, powerful, enterprise-ready.

Per-task card issuance

When agent starts a specific task, Troxy spins up a virtual one-time card scoped to that task, merchant, and budget. Task ends — card dies. Ultimate isolation. Requires BaaS partnership (Lithic) but the UX is magical.

Security Ideas

Bypass attempt counter on dashboard

Show users every time an agent tried to go around Troxy directly and was caught. "3 bypass attempts blocked this week." The moment a user sees this — they never uninstall Troxy. This is the single most powerful trust-building UI element we could ship.

Agent fingerprinting

Troxy learns what "normal" looks like for each agent. Travel agent usually books hotels $100-300. If it suddenly tries to charge $4,000 to an unknown merchant — that's anomalous. Flag it regardless of whether it technically passes the policy rules. Behavioral baseline per agent.

Prompt injection detection

When an agent tries to make a payment that doesn't match the session's original task context — flag it. "You asked your agent to book flights. It's trying to buy gift cards. That's suspicious." The LLM intent verification layer we discussed for V3.

Emergency lockdown button

One big red button in the dashboard. Press it — all agents are immediately blocked from all spending. Every card frozen in Troxy. For when something goes very wrong and the user needs to stop everything instantly. Think of it as a nuclear stop-loss.

Anomaly alert: new country

Agent tries to pay a merchant in a country it has never transacted in before — pause and notify. Same logic banks use for fraud detection, applied to agent behavior. "Your shopping agent just tried to buy something from a merchant in Nigeria. Approve?"

Enterprise Ideas

Agent spend dashboard for CFOs

A dedicated finance view — not the technical dashboard, a clean executive summary. Total agent spend this quarter, broken down by department, by agent, by merchant category. Compare to last quarter. Forecast. Export to Excel. The CFO never has to touch Troxy's tech UI — they just get this clean report.

Policy templates marketplace

Pre-built policy sets for common use cases. "E-commerce company starter pack." "SaaS company policy set." "Family safety bundle." One-click install. Companies share and publish their policy templates. Could become a community ecosystem like Terraform modules or GitHub Actions.

White-label for AI platforms

AI companies building agent products don't want to build payment safety themselves. They embed Troxy white-labeled — their users get the safety layer, the AI company gets the credibility, Troxy gets revenue share on every transaction. This is the platform play that could 10x the business.

Compliance export for auditors

One-click export of all agent transactions in audit-ready format. Every transaction with: what was purchased, which agent, which employee authorized the agent, which policy approved it, timestamp, receipt. Turns Troxy's audit trail into a compliance product. Big companies will pay a lot for this.

Wild / Long-Term Bets

Troxy Score — agent trustworthiness rating

A public score for agent products. "This agent has a Troxy Score of 94 — it has processed 50,000 transactions with a 0.02% anomaly rate." Like a credit score, but for AI agents. Developers display it as a trust badge. Users check it before giving an agent their card. Becomes the standard signal of agent payment safety. This could be bigger than the product itself.

Troxy as the de-facto MCP payment standard

Right now MCP is young and nobody owns "the safe payment tool for agents." If Troxy ships first, gets developer adoption, and becomes the default — developers will write Troxy into their agent code from day one. Switching cost becomes enormous. Troxy schema becomes the lingua franca of agent payments. This is the Microsoft Office / Excel moat applied to agent tooling.

AI-to-AI payments

The future isn't just humans giving agents money. It's agents paying other agents for services. An orchestrator agent hires a specialized research agent, pays it per task. Troxy sits between them — enforcing policies even in agent-to-agent transactions. This is a 2027+ problem but positioning Troxy early here could be enormous. We'd be the trust layer for the entire agentic economy.

Troxy Escrow — conditional payments

"Pay the contractor only if the work is delivered and verified." Agent hires a freelancer, payment is held in escrow by Troxy, released only when another agent or the human confirms delivery. Smart contract logic without blockchain complexity. Could completely reshape how agents handle service payments.

Troxy for subscriptions — agent subscription manager

Agents sign up for things on your behalf. SaaS trials, newsletters, memberships. Troxy tracks every recurring charge an agent created, surfaces them in a "subscriptions" tab, and lets you cancel with one click. "Your agents have signed you up for 7 recurring charges totalling $340/month. Here they are." Subscription management that didn't exist before agents existed.

Behavioral policy learning

Troxy watches your agent's spending patterns for 30 days and suggests policies automatically. "We noticed your travel agent always books economy class under $500. Want us to create a policy that blocks anything over $600 for flights?" The system teaches itself your preferences and turns them into rules. Policies write themselves.

Troxy Wallet — pre-funded agent account

Instead of connecting a real card, users fund a Troxy wallet with a specific amount. Agents spend from the wallet only. When it's empty — done. Like a prepaid gift card for your AI. Consumer-friendly, low-risk, no card details ever involved. This could be the on-ramp for users too scared to connect a real card.

Real-time spending map

A live geographic map on the dashboard showing where your agents are spending. Dots appearing in real time — Tel Aviv, London, New York. Beautiful, visceral, immediately communicates scale and reach. Also a security feature — if dots appear in unexpected countries, something is wrong. Purely a delight feature but the kind people screenshot and share.

Troxy API for developers — build your own rules

A public API that lets developers write custom policy logic beyond the UI. "If the merchant's website contains the word 'crypto', block." "If the total spend across all agents today exceeds $1,000, lock everything down." Programmable policies for power users. Turns Troxy into a platform, not just a product.

Carbon footprint tracking per transaction

Wild but: every purchase your agent makes has a carbon footprint estimate. Flight bookings, physical goods, digital services. Troxy shows total estimated carbon generated by your agents this month. Companies with sustainability goals would pay for this. Nobody in the agent space is even thinking about this yet.

Distribution Ideas

Troxy Chrome extension

For users who don't want to install a daemon. Extension watches for MCP payment calls in the browser, intercepts them, shows a quick approve/block popup before the charge fires. Lightweight, zero install friction, works on any OS. Perfect consumer on-ramp and a great ProductHunt launch.

Troxy mobile app — approvals on the go

The approval notification is powerful on mobile. Agent needs approval — phone buzzes — user sees the charge — one tap to approve or block. The app is essentially a smart notification center for everything your agents are trying to do. Simple, beautiful, one purpose. Could go viral just from the UX alone.

"Troxy-verified" badge for agent products

Developers who integrate Troxy get a badge they can put on their product page. "Troxy-verified: all payments enforced." Like the SSL padlock but for agent safety. Creates social proof, drives developer adoption, makes Troxy a brand signal not just a tool.

Troxy Stories — social proof feed

Opt-in anonymous feed of interesting Troxy blocks. "A travel agent tried to book 14 identical flights in 3 seconds — blocked." "A shopping agent was hijacked via prompt injection and tried to send $2,000 to an unknown merchant — blocked." Real stories, anonymized, building the case for why this matters. Think Cloudflare's radar reports but for agent payments.

The north star

Every idea above points at the same thing: Troxy becomes the trust infrastructure for the entire agentic economy. Not just "a tool that blocks bad charges" — but the layer that makes humans comfortable giving AI agents real autonomy, because they know Troxy is watching. The more agents exist, the more valuable Troxy becomes. That's the compounding flywheel.


Tech Plan, Languages & Architecture
Two clearly separate architectures: MVP (weeks 1–4, demo to investors, zero real customers) and Prod (post-funding, real customers, real scale). We build MVP first and only add complexity when we actually need it. This is the responsible way to spend investor money.
The core principle

Every architectural decision at MVP stage is justified by one question: does this help us demo to investors in 4 weeks? If no — it waits. Investors want to see the product work, not admire the infrastructure. We show them we're cost-aware by proving we can do more with less.

Languages — same for both MVP and Prod

ComponentLanguageWhy
Daemon (local process) Go Single binary, zero dependencies, cross-compiles to Mac/Linux/Windows in one command. Same approach as ngrok, Terraform, Cloudflare WARP. Users run npx troxy init and get a native binary — no Node.js runtime required.
Backend (Lambda) TypeScript (Node.js) MCP ecosystem is JS-first. Anthropic's SDK is TypeScript. Fast to iterate on. Lambda means zero idle cost — we only pay per invocation, not per hour. At MVP scale with 10 test users, this costs effectively $0.
Dashboard Next.js (TypeScript) Next.js static export — no SSR. All data fetching client-side. Deployed via GitHub Actions to S3 + CloudFront. Claude Code turns the mockup into real React fast.
Infrastructure Terraform + Terragrunt Gilad knows this cold from Rapyd. Same OIDC pattern, same module structure. Moving from MVP to Prod is just copying one folder and changing an account ID.
Database PostgreSQL (RDS) Structured queries, filtering by agent/date/policy/amount. The audit log needs to be queryable, not just stored. NoSQL won't work here.

MVP Architecture — one Lambda, one database

Why one Lambda is enough for MVP

We have zero real customers during MVP. A user with 10+ policies is just 10+ rows in a table — a SELECT that takes microseconds. There is no scale problem to solve. One Lambda doing everything is faster to build, easier to debug, and just as correct as four Lambdas. We add complexity only when we hit actual limits.

# MVP: one Lambda does everything

Daemon → API Gateway → ONE Lambda (core-handler) → RDS PostgreSQL
                                    ↓
                              + AWS SES (email)

The Lambda:
  1. Receives MCP call from daemon
  2. Validates API token (bcrypt check vs RDS)
  3. Loads user policies from RDS (ORDER BY priority)
  4. Evaluates policies top-to-bottom — first match wins
  5. Checks budget envelope (SELECT FOR UPDATE on RDS)
  6. Updates envelope if ALLOW
  7. If ESCALATE → fires AWS SES email, stores pending_approval
  8. Writes to audit_log
  9. Returns ALLOW / BLOCK / ESCALATE to daemon

+ ONE approval Lambda (tiny, only handles email link clicks):
  approval-webhook → reads pending_approvals → resolves + notifies
ComponentMVP choiceCostWhy not the complex version
Lambda count2 (core-handler + approval-webhook)$0 (free tier)4 Lambdas = 4x the debugging surface with no benefit at zero scale
Envelope trackingRDS with SELECT FOR UPDATE$0 extraRedis ($15/mo) is correct at scale — overkill for 10 test users
Event busNone — synchronous calls$0EventBridge adds async complexity with no benefit at MVP
Auth between daemon + APISigned API token + HTTPS$0mTLS is fiddly to configure and adds days of work — token + TLS is secure enough for demo
Total monthly AWSRDS t3.micro only~$20/moFull prod stack would be ~$55/mo — we save $35/mo with no functional difference

Prod Architecture — split when we hit real limits

This is what the architecture becomes after funding, with real customers. Nothing here is needed for the investor demo — but having it documented shows investors we've thought past MVP.

# PROD: split Lambdas, add Redis, add EventBridge

Daemon → API Gateway → mcp-proxy Lambda
                            ↓ invoke
                        policy-engine Lambda    ← reads Redis (fast envelopes)
                            ↓ EventBridge event
                        audit-logger Lambda     ← async, doesn't slow decision
                        notification-handler Lambda

ElastiCache Redis    ← atomic envelope ops, sub-5ms
RDS PostgreSQL       ← audit trail, policies, users
What changesWhy we add itWhen to add it
Split into 4 LambdasIndependent scaling per function, cleaner IAM, audit logging doesn't block policy decisionFirst paying customers
ElastiCache RedisAtomic envelope ops at scale — RDS can't handle 1000s of concurrent updates safelyWhen concurrent users hit RDS limits
EventBridgeDecouples audit logging — decision returns instantly, logging happens asyncWhen latency becomes a concern
mTLSEnterprise customers require it for security complianceBefore first enterprise deal

Cost comparison — MVP vs Prod

ServiceMVP costProd costWhen it grows
Lambda (all functions)$0~$5–20/moAfter 1M requests/mo
RDS PostgreSQL (t3.micro)~$20/mo~$40/mo (t3.small)When DB CPU >60% consistently
ElastiCache Redis$0 (not needed)~$15/mo (t3.micro)When concurrent envelope writes cause contention
API Gateway$0~$3–10/moAfter 1M calls/mo
S3 + CloudFront$0~$2/moAfter 1TB transfer/mo
S3 + CloudFront (dashboard)~$0Stays cheap at scaleNever needs upgrading
Claude API~$10–20/mo~$50–200/moScales with transaction volume
Total AWS + infra~$30–40/mo~$120–300/moGrows with real usage — not before
What to say to investors about cost

"Our MVP runs on a single Lambda and one Postgres instance — $30/month. We've deliberately kept the architecture flat until we have real traffic. Every component we add in production has a specific trigger that justifies it. We don't add complexity speculatively." This shows financial discipline and engineering maturity — exactly what seed investors want to hear.


Repo Structure
Three repos. Clean separation of concerns. One AWS account to start — troxy-mvp. When we need prod, copy the folder, change the account ID. Terragrunt makes this trivial.

The three repos

troxy-tf-modules — reusable Terraform modules
troxy-tf-modules/
├── rds/
│   ├── main.tf          ← postgres instance
│   ├── variables.tf
│   └── outputs.tf       ← endpoint, port, db_name
├── elasticache/
│   ├── main.tf          ← redis cluster
│   ├── variables.tf
│   └── outputs.tf       ← endpoint, port
├── lambda/
│   ├── main.tf          ← function + IAM role
│   ├── variables.tf
│   └── outputs.tf       ← function_arn, invoke_url
├── api-gateway/
│   ├── main.tf
│   ├── variables.tf
│   └── outputs.tf
├── s3-cloudfront/
│   ├── main.tf          ← binary distribution
│   ├── variables.tf
│   └── outputs.tf
└── iam-oidc-github/
    ├── main.tf          ← OIDC federation for GitHub Actions
    ├── variables.tf     ← same pattern built at Rapyd
    └── outputs.tf
troxy-tf-live — actual deployments, calls modules
troxy-tf-live/
├── terragrunt.hcl           ← root config, AWS provider, remote state in S3
├── troxy-mvp/               ← the one account for now
│   ├── account.hcl          ← account_id, region
│   ├── rds/
│   │   └── terragrunt.hcl
│   ├── elasticache/
│   │   └── terragrunt.hcl
│   ├── lambda/
│   │   ├── mcp-proxy/
│   │   │   └── terragrunt.hcl
│   │   ├── policy-engine/
│   │   │   └── terragrunt.hcl
│   │   ├── notification-handler/
│   │   │   └── terragrunt.hcl
│   │   └── audit-logger/
│   │       └── terragrunt.hcl
│   ├── api-gateway/
│   │   └── terragrunt.hcl
│   ├── s3-cloudfront/
│   │   └── terragrunt.hcl
│   └── iam-oidc-github/
│       └── terragrunt.hcl
└── .github/
    └── workflows/
        └── terraform.yml    ← OIDC, plan on PR, apply on merge

When we need prod: copy troxy-mvp/troxy-prod/, update account.hcl. Done.

troxy-dashboard — Next.js frontend
troxy-dashboard/
├── app/
│   ├── (auth)/
│   │   └── login/
│   ├── dashboard/
│   │   ├── page.tsx         ← overview
│   │   ├── cards/
│   │   ├── policies/
│   │   ├── agents/
│   │   ├── activity/
│   │   └── insights/
│   └── api/                 ← Next.js API routes → calls api.troxy.ai
├── components/
│   ├── ui/
│   └── dashboard/
├── lib/
│   └── api.ts               ← typed API client
└── .github/
    └── workflows/
        └── deploy.yml       ← GitHub Actions: build + s3 sync + CF invalidation

Remote state config (root terragrunt.hcl)

# terragrunt.hcl
remote_state {
  backend = "s3"
  config = {
    bucket  = "troxy-mvp-tf-state"
    key     = "${path_relative_to_include()}/terraform.tfstate"
    region  = "us-east-1"
    encrypt = true
  }
}

generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite"
  contents  = <<EOF
provider "aws" {
  region = "us-east-1"
}
EOF
}

GitHub Actions workflow (terraform.yml)

# Same OIDC pattern as rapyd-financial — swap account ID + role name
name: Terraform
on:
  push:
    branches: [main]
  pull_request:

jobs:
  terraform:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::ACCOUNT_ID:role/TroxyGithubTerraform
          aws-region: us-east-1

      - name: Terragrunt plan
        if: github.event_name == 'pull_request'
        run: terragrunt run-all plan

      - name: Terragrunt apply
        if: github.event_name == 'push'
        run: terragrunt run-all apply --auto-approve

First steps in AWS (before Terraform)

These four things must be done manually — everything else Terraform handles:

  1. Create AWS account — troxy-mvp
  2. Enable IAM Identity Center (SSO) — never use root credentials
  3. Create S3 bucket manually — troxy-mvp-tf-state (must exist before Terraform can store state)
  4. Create the OIDC GitHub role — TroxyGithubTerraform (bootstrap manually first time, then manage in TF)

Security Architecture
Security built into every layer from day one — not bolted on after. Given that Troxy sits between users and their payment methods, this is non-negotiable.

Layer 1 — Network

  • All traffic TLS 1.3 minimum — no exceptions
  • API Gateway accepts HTTPS only
  • RDS and Redis in private subnet — no public internet access
  • Security groups: Lambda → RDS on port 5432 only, Lambda → Redis on port 6379 only
  • Nothing else can reach RDS or Redis
  • No NAT Gateway — Lambda in public subnet with tight security groups (saves $32/mo and is perfectly secure for our architecture)

Layer 2 — Authentication

  • Every daemon request carries: Authorization: Bearer <token>
  • Token stored as bcrypt hash in RDS — never plaintext, ever
  • API Gateway rejects any request without a valid token
  • Tokens are per-machine, per-user, revocable instantly from dashboard
  • PROD ONLY mTLS between daemon and API Gateway — add before first enterprise customer, not for MVP

Layer 3 — Secrets

  • Zero secrets in code or environment variables — ever
  • All secrets in AWS Secrets Manager (DB password — SES uses IAM role (no secret needed))
  • Lambda reads secrets at cold start, caches in memory
  • KMS encrypts everything at rest: RDS, Redis, S3, Secrets Manager
  • GitHub Actions uses OIDC — no long-lived AWS keys stored anywhere

Layer 4 — Data

  • Postgres encrypted at rest (AWS managed KMS key)
  • Redis encrypted at rest + in transit
  • S3 bucket: private, no public access, versioning enabled
  • Card numbers NEVER stored — only aliases + last 4 digits
  • Audit logs immutable — append only, no deletes allowed

Layer 5 — Application

  • Input validation on every Lambda endpoint
  • SQL via parameterized queries only — no string concatenation
  • Rate limiting on API Gateway (per token, per IP)
  • CORS locked to dashboard.troxy.ai only
  • Each Lambda has minimum IAM permissions — see below

IAM — least privilege per Lambda

LambdaCanCannot
mcp-proxy Read own Secrets Manager secret, invoke policy-engine, invoke audit-logger Touch RDS directly, touch Redis directly
policy-engine Read from Redis (envelopes), read from RDS (policies table), write envelope updates to Redis Invoke other Lambdas, write to RDS, touch S3
notification-handler Call AWS SES via SDK, read/write RDS pending_approvals table Touch Redis, touch S3
audit-logger Write to RDS audit_log table only Read from RDS, touch Redis, touch S3, invoke other Lambdas

Full system architecture diagram

MVP vs Prod — read this first

The diagram below shows the MVP architecture — 2 Lambdas, no Redis, no EventBridge. Section 15 (Tech Plan) explains what gets added post-funding and why. If you're building MVP, follow this diagram. Ignore any references to 4 Lambdas or ElastiCache in earlier sections — those are prod.

┌─────────────────────────────────────────────────────┐
│  USER'S MACHINE                                     │
│                                                     │
│  ┌─────────────────┐     ┌───────────────────────┐  │
│  │ Claude Desktop  │────▶│  Troxy Daemon (Go)    │  │
│  │ Cursor / etc.   │     │  localhost:4242        │  │
│  └─────────────────┘     └──────────┬────────────┘  │
│                                     │               │
│  mcp_config.json rewritten:         │ HTTPS + token │
│  stripe → localhost:4242/stripe     │               │
└─────────────────────────────────────┼───────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────┐
│  AWS troxy-mvp account                              │
│                                                     │
│  API Gateway HTTP API (api.troxy.ai)                │
│       │                                             │
│       ├──▶ Lambda: core-handler   ← MVP: does ALL  │
│       │      validates token (bcrypt vs RDS)        │
│       │      loads policies (SELECT ORDER BY prio)  │
│       │      evaluates rules top-to-bottom          │
│       │      checks budget envelope (SELECT FOR UPDATE)│
│       │      writes audit_log                       │
│       │      fires AWS SES if ESCALATE             │
│       │      returns ALLOW / BLOCK / ESCALATE       │
│       │                                             │
│       └──▶ Lambda: approval-webhook                 │
│              handles approve/decline email clicks   │
│              updates pending_approvals in RDS       │
│              fires AWS SES confirmation            │
│                                                     │
│  RDS PostgreSQL t3.micro  (~$20/mo — only paid svc) │
│  (all data: users, policies, audit_log, envelopes,  │
│   pending_approvals, api_tokens, card_aliases)      │
│                                                     │
│  S3 + CloudFront (free tier)                        │
│  (daemon binaries + install.troxy.ai script)        │
│                                                     │
│  ✗ No Redis (ElastiCache) — added post-funding      │
│  ✗ No EventBridge — added post-funding              │
│  ✗ No mTLS — added before enterprise customers      │
└─────────────────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────┐
│  S3 + CloudFront                                    │
│  dashboard.troxy.io (Next.js static export)         │
│  → all data fetching client-side → api.troxy.io     │
│  → deployed via GitHub Actions on every push        │
└─────────────────────────────────────────────────────┘

Dashboard Deployment
How the Next.js dashboard gets from GitHub to dashboard.troxy.io. Everything managed by Terraform and GitHub Actions. No manual steps after initial setup.
The key decision — static export, no SSR

The dashboard is built as a static Next.js export — no server-side rendering. All data fetching happens client-side via fetch() calls to api.troxy.io. This means it can be hosted on S3 + CloudFront for essentially free, managed entirely by Terraform. Claude Code must be told this explicitly.

AWS resources (all Terraform)

# S3 bucket — stores built dashboard files
aws_s3_bucket "dashboard" {
  bucket = "troxy-dashboard-prod"
  # private — only CloudFront can read it
}

# CloudFront distribution — serves the dashboard globally
aws_cloudfront_distribution "dashboard" {
  origin = s3 bucket above
  aliases = ["dashboard.troxy.io"]
  default_root_object = "index.html"
  # custom_error_response for 404 → index.html (SPA routing)
  price_class = "PriceClass_100"  # US + Europe only — cheapest
}

# ACM certificate — free SSL for dashboard.troxy.io
aws_acm_certificate "dashboard" {
  domain_name = "dashboard.troxy.io"
  region      = "us-east-1"  # must be us-east-1 for CloudFront
}

# Cloudflare DNS record — points to CloudFront
cloudflare_record "dashboard" {
  name  = "dashboard"
  type  = "CNAME"
  value = cloudfront_distribution.domain_name
}

GitHub Actions workflow — deploy.yml

# .github/workflows/deploy.yml in troxy-dashboard repo

name: Deploy Dashboard

on:
  push:
    branches: [main]           # deploy on merge to main
  pull_request:
    branches: [main]           # build check on every PR

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write          # required for OIDC
      contents: read

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build      # next build + next export → ./out
        env:
          NEXT_PUBLIC_API_URL: https://api.troxy.io

      - name: Configure AWS credentials (OIDC)
        if: github.ref == 'refs/heads/main'
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::454983519464:role/TroxyGithubDashboard
          aws-region: us-east-1

      - name: Deploy to S3
        if: github.ref == 'refs/heads/main'
        run: |
          aws s3 sync ./out s3://troxy-dashboard-prod \
            --delete \
            --cache-control "max-age=31536000,immutable"

      - name: Invalidate CloudFront cache
        if: github.ref == 'refs/heads/main'
        run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ secrets.CF_DISTRIBUTION_ID }} \
            --paths "/*"

next.config.js — static export config

// next.config.js — tell Claude Code to use this exactly
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export',            // static export — no SSR
  trailingSlash: true,         // needed for S3 routing
  images: {
    unoptimized: true          // S3 can't do Next.js image optimization
  }
}

module.exports = nextConfig

// All API calls in the dashboard use:
// const API = process.env.NEXT_PUBLIC_API_URL || 'https://api.troxy.io'
// fetch(`${API}/dashboard/activity`)
// Never use getServerSideProps — always useEffect + fetch

Cost

ServiceMVP costAt scale
S3 storage (dashboard files)~$0.01/mo~$0.01/mo — files never change size
CloudFront (data transfer)~$0/mo (free tier)~$1–5/mo at 10K users
ACM certificateFreeFree forever
Total~$0/mo~$1–5/mo
Database Schema
The core PostgreSQL tables. Designed for auditability — every decision is recorded with full context and is immutable.
-- Users and their API tokens
users (
  id            UUID PRIMARY KEY,
  email         TEXT UNIQUE NOT NULL,
  password_hash TEXT,            -- bcrypt(password, cost=12). NULL if magic-link only
  verified_at   TIMESTAMPTZ,     -- NULL = email not yet verified
  created_at    TIMESTAMPTZ DEFAULT now()
)

email_verifications (
  id         UUID PRIMARY KEY,
  user_id    UUID REFERENCES users(id),
  token      TEXT NOT NULL,      -- random 32 bytes, single-use
  expires_at TIMESTAMPTZ NOT NULL,
  used_at    TIMESTAMPTZ         -- NULL = not yet used
)

api_tokens (
  id           UUID PRIMARY KEY,
  user_id      UUID REFERENCES users(id),
  token_hash   TEXT NOT NULL,   -- bcrypt, never plaintext
  name         TEXT,            -- "MacBook Pro", "Work Laptop"
  last_used_at TIMESTAMPTZ,
  revoked_at   TIMESTAMPTZ      -- NULL = active
)

-- Card aliases — real card number NEVER stored
card_aliases (
  id               UUID PRIMARY KEY,
  user_id          UUID REFERENCES users(id),
  alias_name       TEXT NOT NULL,   -- "Gilad's Groceries"
  last_four        TEXT NOT NULL,   -- "1234"
  card_type        TEXT,            -- "visa", "mastercard"
  monthly_budget   NUMERIC,
  budget_used      NUMERIC DEFAULT 0,
  budget_reset_day INTEGER DEFAULT 1
)

-- Registered agents
agents (
  id                    UUID PRIMARY KEY,
  user_id               UUID REFERENCES users(id),
  name                  TEXT NOT NULL,     -- "Romi Agent"
  allowed_card_alias_ids UUID[]
)

-- Policy rules — evaluated top to bottom, first match wins
policies (
  id                UUID PRIMARY KEY,
  user_id           UUID REFERENCES users(id),
  name              TEXT NOT NULL,
  priority          INTEGER NOT NULL,
  agent_id          UUID,           -- NULL = any agent
  card_alias_id     UUID,           -- NULL = any card
  merchant_category TEXT,           -- NULL = any category
  amount_operator   TEXT,           -- 'lt', 'gt', 'pct_over_budget'
  amount_value      NUMERIC,
  action            TEXT NOT NULL,  -- 'ALLOW', 'BLOCK', 'ESCALATE'
  notify_channels   TEXT[]          -- ['email', 'slack']
)

-- Every single transaction attempt — immutable, no deletes
audit_log (
  id                UUID PRIMARY KEY,
  user_id           UUID REFERENCES users(id),
  agent_id          UUID,
  card_alias_id     UUID,
  merchant_name     TEXT,
  merchant_category TEXT,
  amount            NUMERIC NOT NULL,
  currency          TEXT DEFAULT 'USD',
  policy_id_matched UUID,           -- which rule fired
  decision          TEXT NOT NULL,  -- 'ALLOW', 'BLOCK', 'ESCALATE'
  approved_by       TEXT,           -- 'auto' or user email
  approved_at       TIMESTAMPTZ,
  created_at        TIMESTAMPTZ DEFAULT now()
)

-- Held transactions waiting for human approval
pending_approvals (
  id             UUID PRIMARY KEY,
  audit_log_id   UUID REFERENCES audit_log(id),
  user_id        UUID REFERENCES users(id),
  approval_token TEXT NOT NULL,     -- signed, expires in N minutes
  expires_at     TIMESTAMPTZ NOT NULL,
  resolved_at    TIMESTAMPTZ,
  resolution     TEXT              -- 'APPROVED', 'DECLINED', 'EXPIRED'
)

Local Dev Setup
The full Troxy stack running on your laptop in one command. Zero AWS costs during development. No real credit card. No real money. This is how you build and iterate every day.
The key insight — you never need a real card to test

Troxy intercepts the MCP call before it reaches the real payment provider. So for testing, you replace Stripe's real MCP server with a fake one that always returns "success". The agent never knows the difference. No real card, no real charges, no real money — ever during development.

How the fake Stripe MCP works

Real flow (production):
Agent → Troxy daemon → Troxy API → real Stripe MCP → real charge 💳

Test flow (local dev):
Agent → Troxy daemon → Troxy API → fake Stripe MCP → returns "success" 🧪
                                                      (no money moves, ever)

Fake Stripe MCP server (20 lines)

This is all you need to simulate the payment provider. It accepts any MCP tool call, logs it so you can see exactly what Troxy sent, and returns a success response.

// fake-stripe-mcp/index.ts
import express from 'express'
const app = express()
app.use(express.json())

app.post('/tools/:toolName', (req, res) => {
  console.log(`💳 MCP call intercepted: ${req.params.toolName}`, req.body)

  // Pretend to be Stripe — return success for everything
  res.json({
    success: true,
    payment_id: 'fake_' + Date.now(),
    amount: req.body.amount,
    merchant: req.body.merchant,
    status: 'completed'
  })
})

app.listen(3001, () =>
  console.log('🟢 Fake Stripe MCP running on localhost:3001')
)

docker-compose.yml — full local stack

services:

  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: troxy
      POSTGRES_PASSWORD: localdev
    ports: ["5432:5432"]

  fake-stripe-mcp:
    build: ./fake-stripe-mcp
    ports: ["3001:3001"]
    # Logs every MCP call so you can see what Troxy forwarded

  troxy-api:
    build: ./backend
    environment:
      DATABASE_URL: postgres://postgres:localdev@postgres/troxy
      POSTMARK_API_KEY: "POSTMARK_API_TEST"  # sandbox mode — no real emails
      FAKE_MCP_URL: http://fake-stripe-mcp:3001
    ports: ["3000:3000"]
    depends_on: [postgres, fake-stripe-mcp]

Starting the local stack

# 1. Start everything
docker-compose up

# 2. Start the daemon pointing at local API (not prod)
TROXY_API_URL=http://localhost:3000 troxy daemon start

# 3. Verify it's running
curl http://localhost:3000/health
# → {"status":"ok","db":"connected"}

# 4. Manually fire a test MCP call
curl -X POST http://localhost:4242/stripe/tools/create_payment \
  -H "Authorization: Bearer test_token_123" \
  -H "Content-Type: application/json" \
  -d '{"amount": 299, "merchant": "Ahrefs", "category": "software"}'

# 5. Check the logs — you should see:
# troxy-api:        ✅ ALLOW — policy matched, forwarding
# fake-stripe-mcp:  💳 MCP call intercepted: create_payment {amount:299...}

Real services during testing

ServiceDev / localInvestor demoReal users
Payment providerFake Stripe MCP (Docker)Stripe test mode — card 4242 4242 4242 4242Real Stripe MCP
Email (AWS SES)Sandbox mode — no real deliveryAWS SES sandbox or realReal AWS SES
DatabaseLocal Postgres (Docker)AWS RDS (troxy-mvp)AWS RDS (troxy-prod)
Real moneyNeverNever (test mode)Only then

How to Test
Three environments, each serving a different purpose. Daily local dev → weekly AWS check → full demo run before every investor meeting.

Environment 1 — Local Docker (daily)

Fastest feedback loop. Zero cost. Catches 80% of bugs. Every code change tested here first.

# Start the stack
docker-compose up

# Run the test suite
npm test                    # unit tests — policy engine logic
npm run test:integration    # full flow against local Docker stack

# Watch logs in real time while Claude makes a call
docker-compose logs -f troxy-api

Environment 2 — AWS troxy-mvp (weekly)

Real AWS. Real Lambda cold starts. Real RDS latency. GitHub Actions deploys here automatically on every push to main. Catches the 20% of bugs Docker misses — IAM permission gaps, Lambda timeouts, VPC networking issues.

Environment 3 — Full end-to-end demo run (before every investor meeting)

Run this checklist the morning of every investor meeting. All 9 steps must pass.

#ActionExpected result
1Run npx troxy initDaemon installs, browser opens dashboard
2Paste API token from dashboardMachine appears as "Online" in sidebar
3Ask Claude: "charge $50 to Rami Levy"AUTO-APPROVE — under budget, right category
4Check dashboard Activity tabTransaction appears with green checkmark ✓
5Ask Claude: "charge $600 to Apple Store"BLOCK — Electronics category policy fires
6Check dashboard — blocked transactionRed X with policy name and reason shown
7Ask Claude: "charge $240 to hotel" (budget $200)ESCALATE — over budget, notification fires
8Check email — approval notificationEmail with Approve / Decline in inbox (not spam)
9Click Approve in emailDashboard updates to approved ✓
This is your investor demo script

Steps 3–9 run live in the meeting. Agent tries to spend → Troxy blocks it → escalates it → human approves from email → dashboard shows the full audit trail. That's the product. That's what gets funded.


Validation Checklist
How to know Troxy is genuinely working — not just appearing to work. The question you need to answer: is the agent's payment really going through Troxy, or is it going around it?
The core question

It's not enough for the dashboard to show a transaction. You need to prove that Troxy was the reason the transaction was allowed or blocked — not that things happened to work out the same way they would have without Troxy.

Level 1 — The block test (strongest proof)

Create a policy that blocks Electronics. Ask Claude to buy AirPods. This is the most definitive test — you cannot fake a block.

Policy: BLOCK Electronics category

Ask Claude: "buy me AirPods for $150"

If Troxy is working:   Claude gets an error. Dashboard shows the block.
If Troxy is bypassed:  Claude succeeds. Nothing in the dashboard.

→ If Claude got blocked, Troxy is real. You cannot fake this.

Level 2 — The database test

Every request that hits Troxy gets a row in the audit log. No row means Troxy never saw it.

# After any agent action, run:
SELECT decision, merchant_name, amount, created_at
FROM audit_log
ORDER BY created_at DESC
LIMIT 5;

Row exists    → Troxy processed it ✅
No row exists + Claude succeeded → Claude went around Troxy ❌

Level 3 — The block-all test (nuclear)

Set a policy to block everything. Ask Claude to buy anything. Nothing should go through.

Policy: BLOCK — all merchants, all amounts, all categories

Ask Claude: "buy me anything — coffee, a book, a pen"

Expected: Claude is blocked every single time. No exceptions.

→ If block-all works, Troxy is genuinely in the middle of
  every payment call. No bypasses possible.

Level 4 — The kill switch test (most important)

This is the ultimate proof. Shut down the Troxy daemon. Try to make a payment.

# Stop the Troxy daemon
troxy daemon stop    # or just kill the process

# Now ask Claude to make a payment

Payment fails  → Troxy was the gateway. It's real. ✅
Payment works  → MCP config not pointing at Troxy. Fix the config. ❌

→ This is your proof of life test.
  If removing Troxy breaks payments, Troxy was genuinely required.

Level 5 — The network proof

Verify at the OS level that Claude's traffic is routing through the daemon.

# While Claude is making a payment, in another terminal:
sudo lsof -i :4242

# You should see two things:
# 1. troxy daemon LISTEN on :4242
# 2. Claude connecting TO :4242

→ Seeing Claude connect to the daemon port = Troxy is
  intercepting the traffic at the network level.
  Claude is NOT talking to Stripe directly.

Run these in order — complete validation:

#TestPass conditionWhat it proves
1Block test — Electronics policy + buy AirPodsClaude blockedTroxy is intercepting and enforcing
2DB test — check audit_log after every actionRow exists in DBTroxy saw and logged every call
3Block-all test — block everything, try anythingNothing gets throughTroxy controls 100% of payment calls
4Kill switch — stop daemon, try paymentPayment failsTroxy is a hard dependency, not optional
5Network test — lsof -i :4242 during paymentClaude connects to daemon portTraffic routes through Troxy at OS level
All 5 pass = Troxy is real

If all 5 levels pass, Troxy is genuinely sitting in the middle of every payment call. Not appearing to — actually doing it. This is what you run before every investor demo and before every new version ships.


Deploy Order & Timeline
4 weeks from zero to investor-demo-ready. Each week has one clear deliverable. If a week slips, the next week still works independently.
WeekWhat we buildDeliverableRunning cost
Week 1troxy-tf-live + modules. OIDC GitHub Actions. RDS + 2 Lambda shells. Local docker-compose with fake Stripe MCP.api.troxy.ai returns 200~$20/mo
Week 2core-handler Lambda logic. MCP call interception. Policy evaluation against RDS. Budget envelope (SELECT FOR UPDATE). Audit log. ALLOW + BLOCK paths.Validation levels 1–4 pass~$20/mo
Week 3ESCALATE path. approval-webhook Lambda. AWS SES approval email. Approve/decline links. Resolution written back to RDS. Full 3-path flow.All 9 demo steps pass~$20/mo
Week 4Next.js dashboard. Real data from RDS. All 5 pages. npx troxy init works. Full validation checklist passes.Investor demo ready~$20/mo

Infrastructure deploy sequence — Week 1

# MVP — lean, 2 Lambdas, no Redis, no EventBridge
1. iam-oidc-github         ← bootstrap manually — GitHub Actions auth
2. s3-cloudfront           ← install.troxy.ai, daemon binaries
3. rds                     ← Postgres t3.micro — only real monthly cost
4. lambda/core-handler     ← all backend logic in one function
5. lambda/approval-webhook ← approve/decline email link handler
6. api-gateway             ← wires both Lambdas to api.troxy.ai

# Explicitly NOT in MVP:
# elasticache  — add when concurrent envelope writes need Redis speed
# eventbridge  — add when async logging latency becomes a concern
# 4 Lambdas    — add when independent scaling is actually needed

Post-funding additions — when triggered, not before

# Trigger-based additions — each has a specific reason
+ elasticache          ← RDS envelope contention under real concurrent users
+ lambda/policy-engine ← need independent scaling from core-handler
+ lambda/audit-logger  ← audit logging blocking decision latency
+ lambda/notification  ← notification volume needs dedicated function
+ eventbridge          ← decoupling audit from decision path
+ rds → t3.small       ← DB CPU above 60% consistently
+ mTLS                 ← first enterprise customer requires it

# All modules are already written in troxy-tf-modules.
# Adding prod components = uncomment + deploy. No rewrite.

Claude Code Strategy
The plan: document everything here first, then hand the full spec to Claude Code and let it build. This document IS the spec. The goal is to save 3–4 weeks of build time without sacrificing understanding of what was built.
The right mental model

Claude Code is a very fast junior developer. It writes a lot quickly, but needs an experienced engineer — Gilad — to catch subtle mistakes. The workflow is: Claude Code writes the first draft, Gilad reviews critically, iterate. Not: Claude Code builds it, Gilad deploys it blindly.

What Claude Code handles well

ComponentWhy Claude Code is good hereTime saving
Terraform modulesRepetitive, boilerplate-heavy, well-defined inputs/outputs. Perfect for code generation.5 days → 2 days
Next.js dashboardFull HTML mockup already exists. Claude Code converts mockup → real React components with real API calls.2 weeks → 4 days
TypeScript LambdaPolicy evaluation logic, audit log writes, AWS SES integration. Logic is well-defined in this doc.1 week → 2–3 days
DB schema + migrationsSchema is fully defined in Section 18. Claude Code writes the SQL and migration scripts.1 day → 2 hours
docker-compose + fake MCPFully specified in Section 19. Pure boilerplate, Claude Code nails this.1 day → 1 hour

Where Gilad leads — Claude Code assists

ComponentWhy Gilad leads
Go daemonCross-compiling for Mac/Linux/Windows, OS-specific service setup (launchd vs systemd), MCP config file interception per OS. Claude Code helps but Gilad must understand and validate every line.
MCP interception layerMCP spec is new and evolving. Claude Code may confidently write something subtly wrong. Read the Anthropic MCP docs yourself first, then use Claude Code with that understanding as a guide.
Approval token securityThe signed approval token (expires in 10min, single-use, cryptographically verified) must be reviewed personally. A subtle bug here is a real vulnerability — this is not a place to trust output blindly.
AWS networkingVPC, security groups, subnet config. Gilad knows AWS networking better than Claude Code does. Trust your instincts over its output here.

How to give tasks to Claude Code

The right way to use Claude Code: write a clear spec for each component (what it does, inputs, outputs, constraints, what NOT to do), give it the spec, review critically.

// Good Claude Code prompt example:
"Build the core-handler Lambda function based on this spec:
- TypeScript, Node.js 20, AWS Lambda
- Receives MCP tool call from daemon via API Gateway
- Validates API token against RDS (bcrypt compare)
- Loads user policies from RDS ordered by priority ASC
- Evaluates each policy top-to-bottom, first match wins
- On ALLOW: checks budget envelope with SELECT FOR UPDATE
  updates envelope, writes audit_log, returns {decision:'ALLOW'}
- On BLOCK: writes audit_log, returns {decision:'BLOCK', reason}
- On ESCALATE: writes audit_log, writes pending_approvals,
  calls AWS SES with approval email, returns {decision:'ESCALATE'}
- Never store card numbers. Never log tokens.
- Database schema is in [attach Section 18 of this doc]
- Connection strings from AWS Secrets Manager, not env vars"

// Bad Claude Code prompt:
"Build the backend for my payment proxy startup"
// → too vague, output will need massive rework

Time estimate — with vs without Claude Code

Without Claude CodeWith Claude Code
Terraform modules5 days2 days
TypeScript Lambda1 week2–3 days
Dashboard (Next.js)2 weeks4–5 days
Go daemon2 weeks1 week (Gilad leads)
docker-compose + fake MCP1 day1–2 hours
Total to demo6–8 weeks3–4 weeks
The plan

This internal document is the spec. When it's complete and reviewed by both founders, hand it to Claude Code section by section. Start with Terraform (lowest risk, most boilerplate), then Lambda, then dashboard. Keep the Go daemon and MCP interception for Gilad to lead with Claude Code assisting. Review every output before committing.


API Contract
The exact interface between every component. This is what Claude Code needs to build the daemon and the Lambda independently and have them work together on first connection. Every endpoint, every field, every response code — fully specified.
AWS services used

API Gateway HTTP API (not REST API — HTTP API is cheaper and faster for our use case) → routes to Lambda. All endpoints require Authorization: Bearer <token> except /health. Base URL: https://api.troxy.ai

Authentication header — every request

Authorization: Bearer troxy_<base64url_random_32_bytes>

# Example:
Authorization: Bearer troxy_dGhpcyBpcyBhIHRlc3QgdG9rZW4K

# Token format: "troxy_" prefix + base64url(32 random bytes)
# Stored in RDS as: bcrypt(token, cost=12)
# Never stored in plaintext anywhere

POST /evaluate — core endpoint

The daemon calls this for every MCP payment tool call it intercepts. The Lambda evaluates the request against the user's policies and returns a decision. Must respond in under 300ms.

# REQUEST
POST https://api.troxy.ai/evaluate
Authorization: Bearer txy-xxx
Content-Type: application/json

{
  "request_id":        "uuid-v4",              // generated by daemon, for idempotency
  "agent_id":          "uuid-v4",              // which agent made the call
  "card_alias_id":     "uuid-v4",              // which card alias to charge
  "mcp_tool":          "stripe_create_payment",// exact MCP tool name called
  "merchant_name":     "Apple Store",
  "merchant_category": "electronics",          // MCC category string
  "amount":            599.99,                 // always in USD, float
  "currency":          "USD",
  "task_context":      "User asked: buy AirPods Pro" // raw agent task description
}

# RESPONSE — ALLOW
HTTP 200
{
  "decision":      "ALLOW",
  "audit_log_id":  "uuid-v4",
  "reason":        "matched policy: Default Allow under $500",
  "forward_to":    "https://mcp.stripe.com"   // daemon forwards original call here
}

# RESPONSE — BLOCK
HTTP 200
{
  "decision":     "BLOCK",
  "audit_log_id": "uuid-v4",
  "reason":       "matched policy: Block Electronics",
  "policy_name":  "Block Electronics",
  "show_user":    "This purchase was blocked by your Troxy policy."
}

# RESPONSE — ESCALATE
HTTP 200
{
  "decision":        "ESCALATE",
  "audit_log_id":    "uuid-v4",
  "approval_id":     "uuid-v4",
  "reason":          "amount $599.99 exceeds budget envelope ($500 remaining)",
  "show_user":       "Approval request sent to your email.",
  "expires_in_secs": 600                      // 10 minutes
}

POST /approve/:approval_id — approval webhook

Called when the user clicks Approve or Decline in their email. Handled by the approval-webhook Lambda. The approval token is in the URL — it is signed and single-use.

# Approve
GET https://api.troxy.ai/approve/<approval_id>?token=<signed_token>&action=approve

# Decline
GET https://api.troxy.ai/approve/<approval_id>?token=<signed_token>&action=decline

# RESPONSE — success (redirect to dashboard confirmation page)
HTTP 302
Location: https://dashboard.troxy.ai/approved?id=<approval_id>

# RESPONSE — expired token
HTTP 200 HTML page: "This approval link has expired. Open your dashboard to review."

# RESPONSE — already resolved
HTTP 200 HTML page: "This request was already resolved."

# Signed token = HMAC-SHA256(approval_id + expires_at, SECRET_KEY)
# SECRET_KEY stored in AWS Secrets Manager — never in code
# Single-use: resolved_at is set on first click, subsequent clicks rejected

GET /health — health check

# No auth required
GET https://api.troxy.ai/health

# RESPONSE
HTTP 200
{
  "status": "ok",
  "db":     "connected",
  "ts":     "2026-03-27T10:00:00Z"
}

# If DB unreachable:
HTTP 503
{ "status": "degraded", "db": "unreachable" }

# Used by UptimeRobot to monitor status.troxy.ai
# Also used by daemon to verify connectivity on startup

GET /dashboard/activity — dashboard data

GET https://api.troxy.ai/dashboard/activity?limit=50&offset=0
Authorization: Bearer txy-xxx

HTTP 200
{
  "items": [
    {
      "id":               "uuid-v4",
      "agent_name":       "Shopping Agent",
      "card_alias_name":  "Gilad's Groceries",
      "merchant_name":    "Rami Levy",
      "merchant_category":"grocery",
      "amount":           49.90,
      "currency":         "USD",
      "decision":         "ALLOW",        // "ALLOW" | "BLOCK" | "ESCALATE"
      "policy_name":      "Default Allow",
      "created_at":       "2026-03-27T10:00:00Z"
    }
  ],
  "total": 142,
  "has_more": true
}

GET /dashboard/insights — Insights V1 (SQL only)

GET https://api.troxy.ai/dashboard/insights?period=30d
Authorization: Bearer txy-xxx

HTTP 200
{
  "period_days": 30,
  "total_spent": 1247.50,
  "total_blocked": 340.00,
  "decisions": { "ALLOW": 87, "BLOCK": 12, "ESCALATE": 5 },
  "top_merchants": [
    { "name": "Rami Levy", "category": "grocery", "total": 342.00 }
  ],
  "by_category": [
    { "category": "grocery", "total": 342.00 }
  ],
  "spend_by_day": [
    { "date": "2026-03-01", "total": 49.90 }
  ]
}

GET /dashboard/envelopes — budget status

GET https://api.troxy.ai/dashboard/envelopes
Authorization: Bearer txy-xxx

HTTP 200
{
  "envelopes": [
    {
      "card_alias_id":   "uuid-v4",
      "alias_name":      "Gilad's Groceries",
      "last_four":       "1234",
      "monthly_budget":  500.00,
      "budget_used":     237.50,
      "budget_remaining":262.50,
      "reset_day":       1
    }
  ]
}

POST /dashboard/policies — create policy

POST https://api.troxy.ai/dashboard/policies
Authorization: Bearer txy-xxx
Content-Type: application/json

{
  "name":               "Block Electronics",
  "priority":           10,
  "agent_id":           null,            // null = any agent
  "card_alias_id":      null,            // null = any card
  "merchant_category":  "electronics",   // null = any category
  "amount_operator":    null,            // null = any amount
  "amount_value":       null,
  "action":             "BLOCK",
  "notify_channels":    ["email"]
}

HTTP 201
{ "id": "uuid-v4", "created_at": "2026-03-27T10:00:00Z" }

# Other policy endpoints:
GET    /dashboard/policies          ← list all policies (ordered by priority)
PATCH  /dashboard/policies/:id      ← update a policy
DELETE /dashboard/policies/:id      ← delete a policy
POST   /dashboard/policies/reorder  ← drag-to-reorder (send full priority array)

POST /tokens — create API token

POST https://api.troxy.ai/tokens
Authorization: Bearer txy-xxx      // existing session token from dashboard login

{ "name": "MacBook Pro Work" }

HTTP 201
{
  "token": "troxy_dGhpcyBpcyBhIHRlc3QK",  // shown ONCE, never again
  "id":    "uuid-v4",
  "name":  "MacBook Pro Work"
}

# Other token endpoints:
GET    /tokens        ← list tokens (name + last_used_at, never the token itself)
DELETE /tokens/:id    ← revoke a token instantly

HTTP error codes — standard across all endpoints

CodeMeaningResponse body
400Missing or invalid request fields{"error":"amount is required"}
401Missing or invalid token{"error":"unauthorized"}
404Resource not found{"error":"policy not found"}
409Duplicate request (same request_id){"error":"duplicate request_id"}
429Rate limit exceeded (API Gateway){"error":"too many requests"}
503Database unreachable{"error":"service unavailable"}

AWS services behind the API

EndpointRoutes toAWS service
POST /evaluatecore-handler LambdaAPI Gateway HTTP API → Lambda → RDS
GET /approve/:idapproval-webhook LambdaAPI Gateway → Lambda → RDS → AWS SES
GET /healthcore-handler LambdaAPI Gateway → Lambda → RDS ping
/dashboard/*core-handler LambdaAPI Gateway → Lambda → RDS
/tokenscore-handler LambdaAPI Gateway → Lambda → RDS

Daemon Spec
The Go binary that runs on the user's machine. This is what makes Troxy invisible — the agent thinks it's talking to Stripe, but it's actually talking to the daemon. Fully specified so Claude Code and Gilad can build it without guessing.

What npx troxy init does — step by step

# npx troxy init runs this sequence:

1. Detect OS (darwin / linux / windows)

2. Detect CPU architecture (amd64 / arm64)

3. Download correct binary from S3/CloudFront:
   https://install.troxy.ai/v1.0.0/troxy-darwin-arm64
   https://install.troxy.ai/v1.0.0/troxy-linux-amd64
   https://install.troxy.ai/v1.0.0/troxy-windows-amd64.exe

4. Verify SHA256 checksum (hardcoded in npm package for that version)

5. Make binary executable: chmod +x troxy

6. Move to user path:
   macOS/Linux: /usr/local/bin/troxy
   Windows:     %APPDATA%\troxy\troxy.exe

7. Run: troxy setup
   → Generates a machine_id (UUID, stored in ~/.troxy/config.json)
   → Opens browser: https://dashboard.troxy.ai/connect?machine_id=xxx
   → User logs in, creates token, copies it
   → User pastes token: "Paste your API token:"
   → Token stored in: ~/.troxy/config.json
   → Daemon verifies token against api.troxy.ai/health

8. Rewrite MCP config (see Section 26)

9. Start daemon:
   macOS:   register launchd service → auto-start on login
   Linux:   register systemd service → auto-start on boot
   Windows: register Windows Service → auto-start on boot

10. Print: "✅ Troxy is running. Dashboard: https://dashboard.troxy.ai"

Config file — ~/.troxy/config.json

{
  "machine_id":   "uuid-v4",
  "api_token":    "txy-xxx",          // stored here, read on startup
  "api_url":      "https://api.troxy.ai",
  "daemon_port":  4242,
  "version":      "1.0.0",
  "mcp_configs":  [                     // list of MCP config files we rewrote
    "~/.config/claude/claude_desktop_config.json",
    "~/.cursor/mcp.json"
  ]
}

Daemon runtime — what it does every second

# On startup:
1. Read ~/.troxy/config.json
2. Verify token: GET api.troxy.ai/health (401 = token revoked, exit)
3. Start HTTP server on localhost:<daemon_port> (default 4242)
4. Log: "Troxy daemon running on port 4242"

# On each incoming MCP call (from Claude Desktop / Cursor / etc.):
1. Receive HTTP request on localhost:4242/<mcp_server>/tools/<tool_name>
2. Extract: tool_name, request body (amount, merchant, etc.)
3. Build evaluate request body (see API contract Section 24)
4. POST to api.troxy.ai/evaluate with Bearer token
5. Read decision from response:
   ALLOW    → forward original request to real MCP endpoint
              return real MCP response to agent
   BLOCK    → do NOT forward
              return error to agent: {"error": "troxy_blocked", "reason": "..."}
   ESCALATE → do NOT forward yet
              poll api.troxy.ai/approval/:id every 5s (timeout: 600s)
              if approved → forward original request → return response
              if declined/expired → return error to agent

# Background goroutine (every 30s):
1. GET api.troxy.ai/health
2. If 401: token revoked — stop accepting new requests, log error
3. If 503: API down — enter fail-open or fail-closed mode (configurable)

Daemon binary — build matrix

OSArchBinary nameBuild command
macOSarm64 (M1/M2/M3)troxy-darwin-arm64GOOS=darwin GOARCH=arm64 go build
macOSamd64 (Intel)troxy-darwin-amd64GOOS=darwin GOARCH=amd64 go build
Linuxamd64troxy-linux-amd64GOOS=linux GOARCH=amd64 go build
Windowsamd64troxy-windows-amd64.exeGOOS=windows GOARCH=amd64 go build

All 4 binaries are built by GitHub Actions on every release tag, uploaded to S3 (install.troxy.ai via CloudFront), and SHA256 checksums are published alongside them.


MCP Interception Mechanism
This is the core of the product. How does Troxy get between Claude and Stripe without the agent knowing? The answer: we rewrite the MCP config file to point at the daemon instead of the real MCP server. The agent never knows the difference.

How MCP servers are configured

Claude Desktop, Cursor, and other MCP-compatible agents read a config file at startup that lists which MCP servers to connect to and where they are. This is the file we rewrite.

# Claude Desktop config file locations:
macOS:   ~/Library/Application Support/Claude/claude_desktop_config.json
Linux:   ~/.config/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json

# Cursor config file locations:
macOS:   ~/Library/Application Support/Cursor/User/globalStorage/mcp.json
Linux:   ~/.config/Cursor/User/globalStorage/mcp.json

Before Troxy — original MCP config

// claude_desktop_config.json — BEFORE troxy init
{
  "mcpServers": {
    "stripe": {
      "command": "npx",
      "args": ["-y", "@stripe/mcp-server"],
      "env": {
        "STRIPE_API_KEY": "sk_live_xxx"
      }
    }
  }
}

After Troxy — rewritten MCP config

// claude_desktop_config.json — AFTER troxy init
{
  "mcpServers": {
    "stripe": {
      "command": "npx",
      "args": ["-y", "@stripe/mcp-server"],    // original kept for forwarding
      "env": {
        "STRIPE_API_KEY": "sk_live_xxx"
      },
      "proxy": {
        "enabled": true,
        "url": "http://localhost:4242/stripe",
        "troxy_card_alias_id": "uuid-of-card-alias"
      }
    }
  }
}

# The highlighted "proxy" block is injected by troxy init.
# Claude Desktop reads this and sends ALL stripe MCP calls
# to localhost:4242/stripe instead of executing stripe directly.
# The daemon intercepts, evaluates, then decides whether to
# forward to the real stripe server or block.

What the daemon does with a forwarded call

# Incoming from Claude Desktop:
POST http://localhost:4242/stripe/tools/create_payment
{
  "amount": 599,
  "currency": "usd",
  "description": "AirPods Pro",
  "customer": "cus_xxx"
}

# Daemon extracts payment fields, calls Troxy API:
POST https://api.troxy.ai/evaluate
{
  "agent_id":          "claude-desktop-machine-uuid",
  "card_alias_id":     "uuid-from-config",
  "mcp_tool":          "create_payment",
  "merchant_name":     "Apple",               // extracted from description
  "merchant_category": "electronics",         // MCC lookup by daemon
  "amount":            599,
  "currency":          "USD"
}

# If ALLOW — daemon forwards original call to real Stripe:
# Spawns the real @stripe/mcp-server process (from original config)
# Pipes the original request to it
# Returns real Stripe response to Claude Desktop
# Claude Desktop never knew Troxy was in the middle

# If BLOCK — daemon returns error to Claude Desktop:
{ "error": "Payment blocked by Troxy policy: Block Electronics" }

# If ESCALATE — daemon holds the call until approved:
# Returns pending status to Claude Desktop
# Polls api.troxy.ai/approval/:id every 5 seconds
# If approved → executes the original call → returns result
# If expired (10min) → returns error to Claude Desktop

MCC (Merchant Category) detection

The daemon needs to figure out the merchant category from the payment description. MVP approach: a static lookup table in the daemon binary.

// mcc_map.go — built into daemon binary
var merchantCategories = map[string]string{
  "apple":      "electronics",
  "amazon":     "retail",
  "uber":       "transport",
  "airbnb":     "travel",
  "booking":    "travel",
  "marriott":   "travel",
  "rami levy":  "grocery",
  "shufersal":  "grocery",
  "ahrefs":     "software",
  "github":     "software",
  "netflix":    "entertainment",
  // ... ~200 common merchants
}

// If merchant not in map → category = "other"
// User can override category per policy rule

Policy Rules Spec
The exact structure of a policy rule, how evaluation works, what operators exist, and the precise logic the Lambda implements. This is what Claude Code needs to build the evaluation engine correctly.

Policy rule — full structure

{
  "id":                 "uuid-v4",
  "user_id":            "uuid-v4",
  "name":               "Block Electronics over $100",
  "priority":           10,              // lower = evaluated first
  "enabled":            true,

  // MATCH CONDITIONS — all must be true for rule to fire (AND logic)
  "agent_id":           "uuid-v4",       // null = any agent
  "card_alias_id":      "uuid-v4",       // null = any card
  "merchant_category":  "electronics",   // null = any category
  "merchant_name":      null,            // null = any merchant (exact match if set)
  "amount_operator":    "gt",            // null = any amount
  "amount_value":       100.00,          // used with operator

  // ACTION — what to do when all conditions match
  "action":             "BLOCK",         // "ALLOW" | "BLOCK" | "ESCALATE"

  // NOTIFICATIONS — who to tell when this rule fires
  "notify_channels":    ["email"]        // ["email"] only for MVP
}

Amount operators

OperatorMeaningExample
gtamount greater than valueBlock if amount > $500
ltamount less than valueAllow if amount < $50 (auto-approve small)
gteamount greater than or equalEscalate if amount ≥ $200
lteamount less than or equalAllow if amount ≤ $100
eqamount exactly equalsRare — for exact subscription amounts
pct_over_budgetamount exceeds remaining envelope by X%Escalate if charge is >10% over remaining budget

Evaluation algorithm — exact logic

This is the precise pseudocode the Lambda implements. Claude Code must follow this exactly.

function evaluateRequest(req, userId):

  // 1. Validate token
  user = validateToken(req.headers.authorization)
  if !user → return 401

  // 2. Idempotency check
  existing = db.query("SELECT * FROM audit_log WHERE request_id = $1", req.request_id)
  if existing → return existing decision (same response, no double processing)

  // 3. Load policies ordered by priority
  policies = db.query(
    "SELECT * FROM policies WHERE user_id = $1 AND enabled = true ORDER BY priority ASC",
    userId
  )

  // 4. Evaluate each policy — first match wins
  matchedPolicy = null
  for policy in policies:
    if policy.agent_id != null AND policy.agent_id != req.agent_id → continue
    if policy.card_alias_id != null AND policy.card_alias_id != req.card_alias_id → continue
    if policy.merchant_category != null AND policy.merchant_category != req.merchant_category → continue
    if policy.merchant_name != null AND policy.merchant_name != req.merchant_name → continue
    if policy.amount_operator != null:
      if !evaluateAmount(req.amount, policy.amount_operator, policy.amount_value) → continue
    matchedPolicy = policy
    break  // first match wins — stop evaluating

  // 5. If no policy matched → default action
  if matchedPolicy == null:
    decision = "ALLOW"   // default: allow if no rule explicitly blocks
    reason = "no matching policy — default allow"
  else:
    decision = matchedPolicy.action
    reason = "matched policy: " + matchedPolicy.name

  // 6. Budget envelope check (only if ALLOW)
  if decision == "ALLOW":
    envelope = db.queryWithLock(
      "SELECT * FROM card_aliases WHERE id = $1 FOR UPDATE",
      req.card_alias_id
    )
    if envelope.monthly_budget != null:
      remaining = envelope.monthly_budget - envelope.budget_used
      if req.amount > remaining:
        decision = "ESCALATE"
        reason = "amount $" + req.amount + " exceeds remaining budget $" + remaining

  // 7. Write audit log
  auditId = db.insert("audit_log", { ...req, decision, policy_id: matchedPolicy?.id })

  // 8. Handle ALLOW — update envelope
  if decision == "ALLOW":
    db.query("UPDATE card_aliases SET budget_used = budget_used + $1 WHERE id = $2",
             req.amount, req.card_alias_id)
    return { decision: "ALLOW", audit_log_id: auditId, forward_to: realMcpUrl }

  // 9. Handle BLOCK
  if decision == "BLOCK":
    if matchedPolicy.notify_channels includes "email":
      ses.send(blockNotificationEmail)
    return { decision: "BLOCK", audit_log_id: auditId, reason, show_user: ... }

  // 10. Handle ESCALATE
  if decision == "ESCALATE":
    approvalId = uuid()
    token = hmacSign(approvalId + expiresAt, SECRET_KEY)
    db.insert("pending_approvals", { approvalId, auditId, token, expiresAt: now+600s })
    ses.send(escalationEmail with approve/decline links)
    return { decision: "ESCALATE", approval_id: approvalId, expires_in_secs: 600 }

Default starter policies — created on signup

Every new user gets these 3 policies automatically. They can edit or delete them.

PriorityNameConditionAction
10Auto-approve smallamount < $50ALLOW
20Escalate largeamount > $200ESCALATE
100Default allowanything elseALLOW

Condition fields — full list (MVP)

FieldOperatorsExample
amount ($)lt, lte, gt, gte, eq, betweenamount greater than 500
amount (% of budget)gt, gte, lt, lteamount % of budget greater than 80 — escalate when over 80% spent
categoryis, is notcategory is electronics
merchant_nameis, contains, starts_with, not_containsmerchant name contains "Amazon"
agent_nameis, is not, is anyagent name is "Shopping Agent"
cardis, is anycard is "Work Expenses"
hour of daylt, gt, betweenhour is between 22:00 and 06:00 → block after hours
day of weekis, is notday is Saturday or Sunday → block on weekends
tx_per_hourgt, gtetransactions per hour greater than 5 → block velocity attack
tx_per_daygt, gtetransactions per day greater than 20
currencyis, is notcurrency is not USD → block foreign currency
merchant_countryis, is notmerchant country is not IL → block outside Israel

Default fallback

Allow by default — like AWS SCPs

When a user first signs up, all transactions are allowed by default. The user creates policies to restrict. This is identical to AWS SCPs — you get a default Allow policy, then you add Deny policies on top. Never block-by-default on a new account — it would break every agent immediately and the user wouldn't understand why.


AI Policy Creator
Instead of building policies with dropdowns, the user types in plain English what they want — and Claude converts it to a structured policy automatically. This is a V2 feature, but it's already planned and the architecture supports it.
Why this matters

The multi-condition rule builder is powerful but complex. Most users want to say "block anything over $500 on weekends except travel" — not click through 4 dropdowns. The AI creator bridges this gap. The structured policy builder stays for power users and for the AI to render its output into.

The flow

# User types in the policy input box:
"Block electronics and entertainment purchases over $100,
 unless it's before 6pm on a weekday"

# Claude API converts this to structured conditions:
{
  "name": "Block high-value leisure purchases",
  "conditions": [
    { "field": "category",    "operator": "eq",  "value": "electronics" },  ← OR
    { "field": "category",    "operator": "eq",  "value": "entertainment" },
    { "field": "amount",      "operator": "gt",  "value": 100 },
    { "field": "hour",        "operator": "gt",  "value": 18 },             ← OR
    { "field": "day_of_week", "operator": "in",  "value": ["Saturday","Sunday"] }
  ],
  "action": "BLOCK"
}

# Dashboard renders it in the visual rule builder
# User can review, tweak, and confirm
# Policy is saved exactly like a manually-created one

Implementation plan (V2)

StepWhatNotes
1Add text input to Policies page"Describe your policy in plain English..." textarea with "Generate" button
2Call Claude API from core-handlerPOST /dashboard/policies/generate → passes text to Claude with structured JSON schema prompt
3Claude returns structured policy JSONUse tool_use / JSON mode to guarantee parseable output. Schema matches existing conditions format.
4Dashboard renders in visual builderUser sees the generated policy in the same multi-condition UI. Can edit before saving.
5User confirms → saved to RDSIdentical to manually-created policy. AI-generated policies get a ✨ badge in the list.

Prompt for Claude Code to implement (V2)

// System prompt for policy generation:
You are a payment policy assistant for Troxy, an AI agent payment control platform.
Convert the user's plain English policy description into a structured JSON policy object.

The policy must use only these fields:
- amount ($): operators: lt, lte, gt, gte, eq, between
- amount_pct (% of budget): operators: gt, gte, lt, lte
- category: values: electronics, grocery, travel, lodging, saas, restaurant, entertainment, gas, pharmacy, clothing, health, education, government, other
- merchant_name: operators: eq, contains, starts_with, not_contains
- agent_name: operators: eq, neq, any
- hour (0-23): operators: lt, gt, between
- day_of_week: values: Monday-Sunday
- tx_per_hour: operators: gt, gte
- tx_per_day: operators: gt, gte
- currency: values: USD, EUR, GBP, ILS, JPY, CAD, AUD
- merchant_country: operators: eq, neq

Action must be: ALLOW, BLOCK, ESCALATE, or NOTIFY.

Return ONLY valid JSON matching this schema:
{
  "name": "string",
  "conditions": [{"field": "string", "operator": "string", "value": "string", "value2": "string|null"}],
  "action": "ALLOW|BLOCK|ESCALATE|NOTIFY"
}
Investor talking point

"We built the full structured policy engine first — AI is a UI layer on top of the same data model. Every AI-generated policy renders in the visual builder for user review. No black box. The user is always in control." This is a much better story than replacing rules with AI — we augment rule creation with AI.


Error Handling
What happens when things go wrong. Every failure mode, what each component does, and what the user sees. Specified so the product degrades gracefully instead of silently breaking.
The key principle — fail closed for payments

When in doubt, block. If Troxy can't reach the API, it should not silently let payments through. The user can always manually approve via the dashboard. An unexpected charge is far worse than a delayed one. The only exception: if the user explicitly sets "fail_mode": "open" in their config.

Daemon error scenarios

ScenarioDaemon behaviorAgent seesUser sees
api.troxy.ai unreachableRetry 3x with 1s backoff → fail closedError: "Troxy unavailable — payment blocked for safety"Dashboard shows daemon offline, Sentry alert fires
Token revoked (401)Stop processing all calls immediatelyError: "Troxy token invalid — payments paused"Email: "Your Troxy token was revoked. Generate a new one."
Daemon crashesOS service manager restarts it (launchd/systemd)Brief error, then recovers automaticallyDashboard shows brief offline blip
/evaluate timeout (>5s)Cancel request, fail closedError: "Troxy evaluation timed out — payment blocked"CloudWatch alarm fires, Sentry logs it
ESCALATE approval timeout (10min)Return DECLINED to agentError: "Approval expired — payment declined"Email: "Your approval request expired."

Lambda (core-handler) error scenarios

ScenarioLambda behaviorHTTP response
RDS unreachableReturn 503, log to CloudWatch, Sentry captures it503 {"error":"service unavailable"}
Invalid request bodyValidate all fields on entry, reject early400 {"error":"amount is required"}
AWS SES fails (email)Log error, still return ESCALATE decision — email failure doesn't block the decision200 ESCALATE (email error logged separately)
Duplicate request_idReturn original decision from audit_log200 with original decision
Lambda cold startAcceptable — first request may take 500–800ms. Not a problem for MVP.Normal response, slightly delayed
Unhandled exceptionSentry captures full stack trace, CloudWatch logs it, Lambda returns 500500 {"error":"internal error"}

AWS services used for observability

WhatAWS serviceAlert when
Lambda error rateCloudWatch Alarm → SNS → emailError rate > 1% in 5 minutes
Lambda durationCloudWatch Alarm → SNS → emailp99 latency > 3 seconds
RDS CPUCloudWatch Alarm → SNS → emailCPU > 80% for 5 minutes
RDS storageCloudWatch Alarm → SNS → emailFree storage < 2GB
API Gateway 5xxCloudWatch Alarm → SNS → emailAny 5xx response
Application errorsSentry (free tier)Any unhandled exception
UptimeUptimeRobot → email + status.troxy.aiapi.troxy.ai/health returns non-200

Approval email content — exact template

This is what the ESCALATE email looks like. AWS SES uses this template. Nothing vague — Claude Code implements this exactly.

Subject: Action needed — your agent wants to spend $240.00

Your AI agent is requesting a payment:

  Agent:     Shopping Agent
  Merchant:  Marriott Hotels
  Amount:    $240.00 USD
  Reason:    20% over your $200 travel budget
  Expires:   In 10 minutes (09:45 PM)

  [ ✅ APPROVE ]   [ ❌ DECLINE ]
  https://api.troxy.ai/approve/<id>?token=xxx&action=approve
  https://api.troxy.ai/approve/<id>?token=xxx&action=decline

If you don't respond, this request will automatically expire.
View your full activity log: https://dashboard.troxy.ai/activity

— Troxy

Secrets Manager keys — exact names

All secrets use these exact key names. Lambda reads them by name from AWS Secrets Manager on cold start.

Secret name (in Secrets Manager)What it containsUsed by
troxy/rds/passwordPostgreSQL master passwordcore-handler, approval-webhook
AWS SES — no secret neededSES uses IAM role attached to Lambda. No API key. Just verify troxy.io domain in SES console once, then Terraform grants Lambda ses:SendEmail permission.core-handler, approval-webhook
troxy/approval/hmac_secretHMAC-SHA256 key for signing approval tokenscore-handler, approval-webhook
troxy/jwt/secretJWT secret for dashboard session tokenscore-handler (dashboard auth)

User Auth, API Keys & Onboarding Flow
How a user creates an account, generates an API key, and connects their machine. The API key is the core of everything — it's how the daemon authenticates, and how users control access.
The correct flow — API key first

User signs up → logs in → generates API key in dashboard → runs npx troxy init --key txy-xxx → daemon starts and is immediately authenticated. The key is the connection. No chicken-and-egg problem.

Full onboarding flow — step by step

Step 1 — Sign up
User visits dashboard.troxy.io → enters email → clicks "Send magic link"
→ AWS SES sends link → user clicks → JWT session created → logged in

Step 2 — Generate API key
Dashboard shows empty state: "Generate your first API key"
→ User clicks "New API key"
→ Names it (e.g. "My MacBook", "Work laptop", "CI server")
→ Key shown ONCE: txy-abc123xyz...
→ User copies it → stored safely (Bitwarden etc.)
→ Dashboard shows key in list: name, created date, last used, status

Step 3 — Connect the machine
npx troxy init --key txy-abc123xyz
→ Daemon authenticates with api.troxy.io using the key
→ MCP config rewritten automatically
→ Machine appears as "Connected" in dashboard

Step 4 — Agent makes a payment
Agent calls Stripe MCP → hits localhost:4242 (daemon)
→ Daemon calls api.troxy.io/evaluate with API key
→ Policy checked → decision made
→ Shows up in dashboard audit log in real time

API key management — what users can do

ActionWhenNotes
Create new keyMVP ✅Name it, shown once, copy it. One key per machine/environment.
List all keysMVP ✅Name, created date, last used date, status (active/revoked). Never show full key again — only last 4 chars.
Revoke a keyMVP ✅Instant. Daemon using that key gets 401 on next call. Machine disconnects.
Rename a keyMVP ✅Just update the label. Useful when machines change.
Per-key permissionsV2e.g. "this key can only evaluate, not manage policies." Useful for CI/CD keys vs human keys.
Key expiryV2Auto-expire keys after 90 days. Enterprise security requirement.
Team keysV3Keys scoped to a team member, not the account owner. Multi-user orgs.

Two token types — do not confuse

TypeFormatUsed byStoredExpires
Dashboard sessioneyJ... (JWT)Browser → dashboard APIlocalStorage7 days
API keytxy-xxxGo daemon → core-handler~/.troxy/config.json + RDS bcrypt hashNever (until revoked)

API key format

# Format:
txy-[32 random alphanumeric chars]

# Example:
txy-k8mN2pQxR7vL9wJ4nF6hD3cA1bE5gI0z

# Storage in RDS (never store plaintext):
api_keys (
  id          UUID PRIMARY KEY,
  user_id     UUID REFERENCES users(id),
  name        TEXT,                    -- "My MacBook"
  key_prefix  TEXT,                    -- "txy-k8mN" (first 8 chars for display)
  key_hash    TEXT,                    -- bcrypt hash of full key
  last_used   TIMESTAMPTZ,
  revoked_at  TIMESTAMPTZ,
  created_at  TIMESTAMPTZ
)

Copy buttons — when key is shown after creation

When a user creates a new API key, the dashboard shows the key exactly once with two copy buttons side by side:

┌─────────────────────────────────────────────────────────────┐
  Your API key — copy it now. It won't be shown again.       
                                                             
  txy-k8mN2pQxR7vL9wJ4nF6hD3cA1bE5gI0z                     
                                                             
  [ Copy key ]   [ Copy install command ]                    
└─────────────────────────────────────────────────────────────┘

"Copy key" copies:
txy-k8mN2pQxR7vL9wJ4nF6hD3cA1bE5gI0z

"Copy install command" copies:
npx troxy init --key txy-k8mN2pQxR7vL9wJ4nF6hD3cA1bE5gI0z
Why two buttons

Most developers will want the full command — they just paste it in terminal and they're done. The "Copy key" button is for people who want to store it in Bitwarden or 1Password first. The install command button is the one-click path to getting started in 10 seconds.

Auth endpoints

POST /auth/magic-link          ← send magic link (no auth required)
POST /auth/verify              ← verify token, return JWT (no auth required)
GET  /auth/me                  ← return current user info (JWT required)

GET  /tokens                   ← list all API keys (JWT required)
POST /tokens                   ← create new API key (JWT required) → returns full key ONCE
DELETE /tokens/:id             ← revoke API key (JWT required)
PATCH /tokens/:id              ← rename API key (JWT required)

Auth roadmap

MethodWhenWhyEffort
Magic linkMVP ✅Simple, secure, no passwordsDone
Google OAuthV2Most users want "Sign in with Google"~2 days
SAML / SSOV3 — first enterprise customerOkta, Azure AD, Google Workspace~1–2 weeks

Budget Reset Mechanism
How monthly budget envelopes reset to zero on the 1st of every month. Needs to be explicit so Claude Code builds it and doesn't leave it as a silent bug.

How it works — EventBridge + core-handler

EventBridge rule: cron(0 0 1 * ? *)  ← midnight UTC, 1st of every month
Triggers: core-handler Lambda with special event body:
  { "type": "budget_reset" }

Lambda detects the event type and runs:
  UPDATE card_aliases SET budget_used = 0 WHERE monthly_budget IS NOT NULL;

Log to CloudWatch: "Budget reset: X envelopes reset at {timestamp}"

Cost: $0 — EventBridge custom events are free, Lambda runs <1 second

Terraform for the EventBridge rule

resource "aws_cloudwatch_event_rule" "budget_reset" {
  name                = "troxy-budget-reset"
  schedule_expression = "cron(0 0 1 * ? *)"
}
resource "aws_cloudwatch_event_target" "budget_reset" {
  rule  = aws_cloudwatch_event_rule.budget_reset.name
  arn   = aws_lambda_function.core_handler.arn
  input = jsonencode({ "type": "budget_reset" })
}
resource "aws_lambda_permission" "eventbridge_budget" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.core_handler.function_name
  principal     = "events.amazonaws.com"
  source_arn    = aws_cloudwatch_event_rule.budget_reset.arn
}
Per-user reset day — V2

The schema has budget_reset_day per alias. For MVP: only support day 1. Run the cron on the 1st and reset all envelopes. Custom reset days (e.g. reset on the 15th per credit card billing cycle) require running a daily check — that's V2.


npm Package & Install Script
Exactly what the npm package contains and what runs when someone does npx troxy init. Claude Code needs this to build the install experience.

Package structure

troxy-npm/
├── package.json       name:"troxy", bin:{"troxy":"./bin/troxy.js"}, node:">=18"
├── bin/troxy.js       the entry point
└── checksums.json     SHA256 per binary, committed at release time:
                       { "darwin-arm64": "abc...", "linux-amd64": "def..." }

bin/troxy.js — install script logic

1. Detect platform: process.platform + process.arch
   darwin+arm64 → darwin-arm64, linux+x64 → linux-amd64, win32+x64 → windows-amd64

2. Download binary from:
   https://install.troxy.ai/v{VERSION}/troxy-{platform}[.exe]

3. Verify SHA256 against checksums.json — throw if mismatch

4. Install to system path:
   macOS/Linux: /usr/local/bin/troxy  (chmod 755)
   Windows:     %APPDATA%\troxy\troxy.exe

5. If cmd is "init": spawn(dest, ["setup"], {stdio:"inherit"})
   → Go binary takes over from here (see Daemon Spec, Section 26)

6. All other cmds: pass through to installed binary
   npx troxy start / stop / status → delegates to Go binary

Release process (GitHub Actions on tag push)

on: push: tags: ["v*"]

1. Cross-compile all 4 Go binaries
2. Calculate SHA256 for each
3. Commit checksums.json to npm package
4. Upload binaries to S3 (install.troxy.ai/v{tag}/)
5. npm publish
6. Create GitHub Release with binaries attached

MCP Config Edge Cases
What the daemon does when MCP config files don't exist, are malformed, or have unexpected content. These scenarios will happen with real users.
ScenarioDaemon behaviorUser sees
Config file not foundSkip silently, continue setup for other appsDashboard: "Claude Desktop not detected — install it and run troxy setup"
Config exists, no payment MCP serversDon't modify. Nothing to intercept.Dashboard: "No payment tools found. Add Stripe MCP to get started."
Proxy block already existsUpdate existing block (token, card_alias_id). No duplicate."Troxy configuration updated"
Config is malformed JSONDon't touch it. Log error."Config file has a JSON error. Fix it and run troxy setup again."
No write permissionShow manual instructions with exact JSON to add."Run sudo troxy setup — or add this JSON manually: ..."
Claude Desktop restarts, overwrites configfs.watch detects change, re-injects proxy block automaticallySeamless — user never notices

Which MCP servers get intercepted — MVP

// payment_mcps.go — built into daemon binary
var paymentMCPServers = []string{
  "stripe",    // MVP: intercept this one only
  "paypal",    // V2
  "shopify",   // V2
  "square",    // V2
}
// Non-payment MCPs (gmail, calendar, etc.) → never touched
Always back up first

Before modifying any config file, the daemon saves claude_desktop_config.json.troxy-backup. Running troxy uninstall restores the original and removes the daemon service cleanly.


UI/UX Guidelines
The visual style and design principles for the dashboard and all Troxy interfaces. No need for a professional design system yet — but Claude Code needs clear direction so it doesn't build something generic. The reference is this document itself.
The reference

Build the dashboard to look and feel exactly like this internal knowledge base. Same fonts, same colors, same card style, same sidebar pattern. This is already validated as a style Gilad likes. It's clean, professional, and distinctive without being flashy.

Fonts — exact values

UseFontWeightGoogle Fonts import
Page titles, section headingsFraunces300, 400, 700family=Fraunces:wght@300;400;700
Body text, labels, navDM Sans300, 400, 500family=DM+Sans:wght@300;400;500
Code, tokens, amountsDM Mono400family=DM+Mono:wght@400

Colors — exact hex values

VariableHexUsed for
--bg#f5f6f8Page background — soft off-white, not pure white
--surface#ffffffCards, sidebar, modals — pure white surfaces on the off-white background
--borderrgba(0,0,0,0.08)All borders — very subtle, almost invisible
--teal#0a9e88 Primary brand color. Active nav, links, buttons, badges, progress bars, callout borders
--teal-lightrgba(10,158,136,0.08)Hover backgrounds, callout backgrounds, active nav item background
--text#1a2235Primary text — dark navy, not pure black
--muted#6b7a99Secondary text, labels, nav links, captions
Green (ALLOW)bg:#e1f5ee fg:#0f6e56Allowed transactions, success states, positive badges
Amber (ESCALATE)bg:#fef3e2 fg:#854f0bEscalated/pending transactions, warning states
Red (BLOCK)bg:#fef2f2 fg:#991b1bBlocked transactions, error states, danger badges

CSS variables — paste this into the dashboard globals

/* globals.css — paste exactly */
:root {
  --bg:          #f5f6f8;
  --surface:     #ffffff;
  --border:      rgba(0,0,0,0.08);
  --teal:        #0a9e88;
  --teal-light:  rgba(10,158,136,0.08);
  --teal-border: rgba(10,158,136,0.22);
  --text:        #1a2235;
  --muted:       #6b7a99;
  --green-bg:    #e1f5ee;
  --green-fg:    #0f6e56;
  --amber-bg:    #fef3e2;
  --amber-fg:    #854f0b;
  --red-bg:      #fef2f2;
  --red-fg:      #991b1b;
}

body {
  font-family: 'DM Sans', sans-serif;
  font-weight: 300;
  background: var(--bg);
  color: var(--text);
  line-height: 1.7;
}

h1, h2, h3 {
  font-family: 'Fraunces', serif;
  font-weight: 400;
  letter-spacing: -0.5px;
}

code, pre, .mono {
  font-family: 'DM Mono', monospace;
}

Layout — match this document

ElementSpec
SidebarFixed left, 260–280px wide, white surface, right border 1px solid var(--border). Logo top, nav links, footer bottom. Active link: teal left border + teal text + teal-light background.
Main contentMargin-left = sidebar width. Max-width ~900px. Padding 48px 56px. bg = var(--bg).
CardsWhite surface, border-radius: 12px, 1px solid var(--border), padding 18–24px. No drop shadows — borders only.
Calloutsborder-left: 3px solid var(--teal), teal-light background, border-radius: 0 8px 8px 0. Use for warnings (amber border) and info (teal border).
TablesFull width, no outer border, row borders only. Header row has bg background. Hover row: teal-light background. Font size 13px.
Buttons (primary)Background var(--teal), white text, border-radius 8px, DM Sans 500, no box-shadow. Hover: darken by 8%.
Buttons (secondary)Background transparent, 1px solid var(--border), text color var(--text). Hover: teal-light background.
Decision badgesALLOW → green badge. BLOCK → red badge. ESCALATE → amber badge. Pill shape, font-weight 500, font-size 11px.

What NOT to do

AvoidWhy
Drop shadows everywhereMakes it look generic and heavy. Borders only.
Rounded corners above 12pxLooks like a consumer app. Keep it professional and precise.
Pure white (#fff) as page backgroundToo harsh. Always use #f5f6f8 as the base, #fff for surfaces on top of it.
Multiple accent colorsTeal is the only brand accent. Green/amber/red are reserved for ALLOW/ESCALATE/BLOCK status only.
Bold body textDM Sans 300 (light) for body, 500 only for labels and emphasis. 700 is reserved for numbers and stats.
Generic sans-serifFraunces for all headings — this is the most distinctive part of the brand. Never substitute with Inter or Arial.
For Claude Code

The full CSS for this style is already written in this document's <style> tag. Copy it directly into the dashboard's globals.css as a starting point. The component patterns (cards, callouts, tables, badges) are all implemented here — replicate them in React/Tailwind. This is not a design you need to invent — it's already built, just port it.


Master Setup Checklist
Everything that needs to exist before writing a single line of code. Every item has a clear pass/fail check — no ambiguity. Green = done, move on. Red = not done, fix before continuing.
Status key

✅ Done — completed and verified. ⏳ Pending — started but waiting (e.g. Yuval verification). ⬜ Todo — not started yet. 🤖 Terraform — Claude Code handles this, not manual.

1. Domain

ItemStatusHow to verifyExpected result
troxy.io registered on Cloudflare✅ DoneCloudflare dashboard → Domains → troxy.io shows ActiveStatus: Active. Registrar: Cloudflare. Expires: March 2027.
DNS nameservers pointing to Cloudflare✅ Donewhois troxy.io → shows Cloudflare nameserversNS records point to Cloudflare (e.g. ns1.cloudflare.com)
troxy.ai — decision pending⏳ DecideDiscuss with Yuval — $80/yr, 2yr minRegister when decided. Update all files in one shot.

2. Email Routing (Cloudflare)

AddressForwards toStatusHow to verify
[email protected][email protected]✅ VerifiedSend email to [email protected] → arrives in personal Gmail
[email protected][email protected]⏳ Yuval must verifyYuval clicks verification link in his Gmail → status turns green in Cloudflare
[email protected][email protected]✅ VerifiedSend email to [email protected] → arrives in personal Gmail
[email protected][email protected]✅ VerifiedSend email to [email protected] → arrives in personal Gmail
[email protected][email protected]✅ VerifiedSend email to [email protected] → arrives in personal Gmail
Catch-all rule[email protected]✅ DoneSend email to [email protected] → arrives in personal Gmail

3. AWS Account

ItemStatusHow to verifyExpected result
AWS account created — Troxy-MVP✅ DoneLogin to SSO portal → see Troxy-MVP accountAccount ID: 454983519464. Region: us-east-1.
Root account email✅ DoneAWS console → Account → root email field[email protected]
Root MFA — Passkey✅ DoneAWS console → Security credentials → MFA devicesShows: Passkeys and security keys — Gilad-MacBook
IAM Identity Center enabled✅ DoneAWS console → IAM Identity Center → shows instance IDInstance: ssoins-72239c69e38b52b8
SSO user: gilad.aslan✅ DoneIAM Identity Center → Users → gilad.aslanStatus: Enabled. Email: [email protected]
Group: Admins + AdministratorAccess✅ DoneIAM Identity Center → Groups → Admins → Membersgilad.aslan is a member. AdministratorAccess permission set assigned to Troxy-MVP.
SSO portal works✅ DoneGo to: d-906606fcd1.awsapps.com/start → loginTroxy-MVP appears with AdministratorAccess button. Click it → enters AWS console.
S3 state bucket created✅ DoneAWS console → S3 → search troxy-mvp-tf-stateBucket exists. Region: us-east-1. Versioning: ON. Public access: blocked.
IAM billing access enabled✅ DoneAWS console → Account → IAM user/role access to billingShows: Activated

4. GitHub

ItemStatusHow to verifyExpected result
Personal account: troxy-tech✅ Donegithub.com/troxy-techPersonal account. Owner of troxy-hq org.
Org: troxy-hq✅ Donegithub.com/troxy-hqOrganization with 3 private repos. Owner: troxy-tech.
Repo: troxy-tf-modules✅ Donegithub.com/troxy-hq/troxy-tf-modulesPrivate repo. Empty. Ready for Terraform modules.
Repo: troxy-tf-live✅ Donegithub.com/troxy-hq/troxy-tf-livePrivate repo. Empty. Ready for Terragrunt deployments.
Repo: troxy-dashboard✅ Donegithub.com/troxy-hq/troxy-dashboardPrivate repo. Empty. Ready for Next.js app.
Add Yuval as org member⏳ Todotroxy-hq → People → Invite member → yuval's GitHubYuval appears as member with appropriate role.

5. External Services

ServiceStatusHow to verifyExpected result
Anthropic API⬜ Todoconsole.anthropic.com → API KeysAPI key created. Store in Bitwarden. Terraform puts it in Secrets Manager.
Bitwarden (password manager)✅ Donevault.bitwarden.com — free individual planPassword manager for all startup accounts. Invite Yuval to shared vault.

6. AWS Infrastructure (via Terraform — Claude Code builds these)

Do not touch AWS console for any of these

Everything below is created by Claude Code via Terraform. Your job: review the Terraform code before applying. Never click-ops these resources into existence.

ResourceStatusHow to verify after Terraform applyExpected result
OIDC GitHub → AWS role🤖 TerraformPush to troxy-tf-live → GitHub Actions runsGitHub Actions authenticates with AWS. No "AccessDenied" errors.
VPC + subnets🤖 TerraformAWS console → VPC → Your VPCsVPC with private subnets in us-east-1a and us-east-1b.
RDS PostgreSQL t3.micro🤖 Terraformpsql -h <endpoint> -U troxy -d troxyConnects successfully. \dt shows 8 tables after migration.
Secrets Manager (4 secrets)🤖 Terraformaws secretsmanager list-secretsShows: troxy/rds/password, troxy/approval/hmac_secret, troxy/jwt/secret, troxy/anthropic/api_key
Lambda: core-handler🤖 Terraformcurl https://api.troxy.io/health{"status":"ok","db":"connected"}
Lambda: approval-webhook🤖 TerraformPOST /evaluate → ESCALATE → email arrivesEmail with Approve/Decline buttons arrives within 10 seconds.
API Gateway HTTP API🤖 Terraformcurl https://api.troxy.io/healthReturns 200. Custom domain api.troxy.io resolves correctly.
S3 + CloudFront (dashboard)🤖 Terraformcurl https://dashboard.troxy.ioReturns HTML. SSL certificate valid. No browser warnings.
AWS SES domain verification🤖 TerraformAWS console → SES → Verified identitiestroxy.io shows as Verified. DKIM enabled. Send test email → lands in inbox, not spam.
EventBridge budget reset rule🤖 TerraformAWS console → EventBridge → Rulestroxy-budget-reset rule exists. Schedule: cron(0 0 1 * ? *). Target: core-handler Lambda.

7. DNS Records (Cloudflare — set by Terraform)

RecordTypePoints toHow to verify
api.troxy.ioCNAMEAPI Gateway custom domaincurl https://api.troxy.io/health → 200
dashboard.troxy.ioCNAMECloudFront distributioncurl https://dashboard.troxy.io → HTML
install.troxy.ioCNAMECloudFront (daemon binaries S3)curl https://install.troxy.io/v1.0.0/checksums.json → JSON
SES DKIM records (3x)CNAMEAWS SES DKIM endpointsSES console → troxy.io → DKIM status: Verified

8. Startup Credits (Yuval owns these)

ProgramStatusWhere to applyWhat you get
AWS Activate⬜ Apply nowactivate.aws$1,000 instant (Founders). Up to $10K+ with HBS nomination. Covers RDS for 12+ months.
Anthropic for Startups⬜ Apply nowanthropic.com/startupsClaude API credits. 3–6 months free. Strong candidate — building MCP infra.
Cloudflare for Startups⬜ Apply nowcloudflare.com/forstartupsCloudflare Pro free for 1 year. WAF, better analytics.
Stripe Atlas⬜ When ready to incorporatestripe.com/atlasDelaware C-Corp formation $500. Bundles $5K+ in credits from AWS, Stripe, and others.

9. Essential Bookmarks

NameURLUse
AWS SSO Portald-906606fcd1.awsapps.com/startDaily AWS login. Never use root.
GitHub Orggithub.com/troxy-hqAll code repos
Cloudflaredash.cloudflare.comDNS, email routing, domain
Anthropic APIconsole.anthropic.comAPI keys, usage, billing
Dashboard (once built)dashboard.troxy.ioThe product
API Health (once built)api.troxy.io/healthFirst thing to check when something breaks
CloudWatch (once built)console.aws.amazon.com/cloudwatchLambda logs, errors, alarms

Current status — summary

AreaStatusRemaining action
Domain✅ DoneDecide on troxy.ai with Yuval
Email routing⏳ 90% doneYuval must verify [email protected]
AWS account✅ DoneNothing — ready for Terraform
GitHub✅ DoneAdd Yuval when he creates GitHub account
Anthropic API⬜ Todoconsole.anthropic.com — 5 minutes
Bitwarden✅ Donevault.bitwarden.com — free individual planGitHub✅ DoneAdd Yuval when he creates GitHub account
Anthropic API⬜ Todoconsole.anthropic.com — 5 minutes
Bitwarden✅ Donevault.bitwarden.com

Current State — April 2026
What is actually built, live, and working as of April 2026. Updated as things ship.
Status

Core API is live. Dashboard is deployed. CLI is published. Policy engine is tested end-to-end from EC2. AWS SES production access pending.

What's Live

ComponentStatusURL / Detail
API (Lambda + API Gateway)✅ Livehttps://wuxyx33bka.execute-api.us-east-1.amazonaws.com
Dashboard✅ Live (Cloudflare Pages)Auto-deploys on push to troxy-hq/troxy-dashboard
RDS PostgreSQL✅ Livedb.t4g.micro, us-east-1. Migrations run on Lambda cold start.
Policy engine (/evaluate)✅ TestedALLOW/BLOCK/ESCALATE/NOTIFY. Tested from EC2 via curl.
CLI (npx troxy)✅ Builtgithub.com/troxy-hq/troxy-cli — MCP server + management commands
Magic link auth✅ LiveSES sandbox mode. Works for verified emails only.
AWS SES production⏳ PendingRequest submitted to AWS. Waiting for approval.
ESCALATE email approval⏳ Not builtPending SES production access. DB tables ready.
Custom domain (api.troxy.ai)⏳ Not setCurrently using raw API Gateway URL

Repos

RepoWhat it containsCI
troxy-hq/troxy-tf-liveTerragrunt live config. Lambda source code at src/core-handler/. Dashboard at files/dashboard/.Targeted Terragrunt apply (only changed modules) + Lambda deploy
troxy-hq/troxy-tf-modulesReusable Terraform modules (networking, RDS, Lambda, etc.)terraform fmt + terraform validate per module
troxy-hq/troxy-dashboardSingle-page dashboard app (index.html + _redirects)Auto-deploy to Cloudflare Pages on push to main
troxy-hq/troxy-cliNode.js CLI — npx troxy init, MCP server, management commandsTest on Node 18/20/22, publish to npm on version tag

CI/CD Pipelines

troxy-tf-live — Targeted Terragrunt

On every push to main, the CI diffs the commit against the previous one and only applies the modules whose files changed. If root.hcl changes, it falls back to run-all.

JobTriggerWhat it does
lintpush + PRterraform fmt -check + terragrunt hclfmt --check
detectpush + PRGit diff → outputs list of changed modules as JSON
plan / <module>PR onlyMatrix job per changed module, posts plan output as PR comment
apply / <module>push to mainMatrix job per changed module — terragrunt apply --auto-approve
plan-all / apply-allroot.hcl changeFallback: terragrunt run-all apply across all modules
Common lint failure

If CI fails on terraform fmt check, run terraform fmt -recursive mvp/ locally and commit the result. The formatter is strict about spacing and single-line variable declarations.

troxy-tf-live — Lambda Deploy

Separate workflow that only triggers when files under src/core-handler/ change. Builds the Python zip, uploads to S3, updates the Lambda function code.

troxy-dashboard — Cloudflare Pages

Push to main in troxy-hq/troxy-dashboard → auto-deploys to Cloudflare Pages in ~30 seconds. PRs get preview URLs automatically.

# To deploy a dashboard change:
cd /path/to/troxy-dashboard
# edit index.html
git add index.html
git commit -m "fix: ..."
git push origin main
# Done. Cloudflare deploys automatically.

troxy-tf-modules — Validate

On every push/PR: terraform fmt -check across all modules, then terraform validate per module (no AWS credentials needed — uses -backend=false).

troxy-cli — Test + Publish

On push/PR: tests run on Node 18, 20, 22. On a version tag push (git tag v0.1.0 && git push --tags): publishes to npm automatically using NPM_TOKEN secret.


CLI Command Reference
Full reference for npx troxy. Works on Mac, Linux, and Windows. Requires Node.js 18+.
How it works

npx troxy init saves your API key to ~/.troxy/config.json and patches the MCP config files for Claude Desktop, Cursor, and Windsurf. On restart, those clients start the Troxy MCP server automatically — which exposes the evaluate_payment tool to any agent.

Setup Commands

# Initialize Troxy — validates key, saves config, patches MCP clients
npx troxy init --key txy-...

# Log in to your dashboard account (for management commands)
npx troxy login

# Log out (clears ~/.troxy/session.json)
npx troxy logout

# Check API health
npx troxy status

Card Commands

# List all cards
npx troxy cards list

# Create a card alias
npx troxy cards create --name "Personal" --budget 500
npx troxy cards create --name "Business" --budget 2000 --provider stripe

# Delete a card alias
npx troxy cards delete --name "Personal"

Policy Commands

# List all policies
npx troxy policies list

# Create a policy — single condition
npx troxy policies create --name "Block high" --action BLOCK --field amount --operator gte --value 100
npx troxy policies create --name "Block gambling" --action BLOCK --field category --operator eq --value gambling
npx troxy policies create --name "Escalate big travel" --action ESCALATE --field amount --operator gte --value 500

# Enable / disable without deleting
npx troxy policies enable  --name "Block high"
npx troxy policies disable --name "Block high"

# Delete a policy
npx troxy policies delete --name "Block high"

Activity

# Show last 20 decisions
npx troxy activity

# Show last 100 decisions
npx troxy activity --limit 100

MCP Server (internal — not called manually)

# Started automatically by Claude Desktop / Cursor / Windsurf.
# The MCP config added by `npx troxy init` looks like this:
{
  "mcpServers": {
    "troxy": {
      "command": "npx",
      "args": ["troxy", "mcp"],
      "env": { "TROXY_API_KEY": "txy-..." }
    }
  }
}

Policy field + operator reference

--fieldValid --operator valuesExample
amountgt, gte, lt, lte, eq, between--field amount --operator gte --value 100
merchant_nameeq, contains, not_contains, starts_with--field merchant_name --operator eq --value Amazon
categoryeq, neq--field category --operator eq --value gambling
agent_nameeq, neq--field agent_name --operator eq --value "my-agent"
currencyeq, neq--field currency --operator neq --value USD
hourlt, gt, between--field hour --operator gt --value 22 (after 10pm UTC)
tx_per_hourgt, gte--field tx_per_hour --operator gt --value 5
tx_per_daygt, gte--field tx_per_day --operator gt --value 20

/evaluate API
The core endpoint called by agents (via MCP or directly). Authenticated with X-Troxy-Key header, not a JWT.

Request

POST /evaluate
X-Troxy-Key: txy-...
Content-Type: application/json

{
  "card_alias":        "Personal",       // required
  "merchant_name":     "Amazon",         // required
  "amount":            50.00,            // required
  "agent":             "my-agent",       // optional
  "merchant_category": "electronics",   // optional
  "merchant_country":  "US",             // optional
  "currency":          "USD"             // optional, default USD
}

Response

// ALLOW
{ "decision": "ALLOW", "policy": "Gilad", "audit_id": "uuid..." }

// BLOCK
{ "decision": "BLOCK", "policy": "Block high amounts", "audit_id": "uuid..." }

// ESCALATE — also creates a pending_approvals record
{ "decision": "ESCALATE", "policy": "Needs approval", "audit_id": "uuid...", "approval_token": "..." }

// NOTIFY — allowed but logged with higher visibility
{ "decision": "NOTIFY", "policy": "Notify on travel", "audit_id": "uuid..." }

// Error cases
{ "error": "invalid or revoked API key" }              // 401
{ "error": "card alias 'Personal' not found" }         // 404

How decisions are made

Policies are evaluated in priority order (lowest number first). First match wins. If no policy matches, the default is ALLOW. Policy conditions support AND and OR logic. Budget is updated on ALLOW and NOTIFY decisions. ESCALATE creates a pending approval and does NOT update the budget until approved.

Testing with curl

# Health check
curl -s https://wuxyx33bka.execute-api.us-east-1.amazonaws.com/health | jq .

# Test evaluate — should ALLOW
curl -s -X POST https://wuxyx33bka.execute-api.us-east-1.amazonaws.com/evaluate \
  -H "Content-Type: application/json" \
  -H "X-Troxy-Key: txy-YOUR_KEY" \
  -d '{"agent":"test","card_alias":"Personal","merchant_name":"Amazon","amount":50}' | jq .

# Test from EC2 (SSM Session Manager)
aws ssm start-session --target i-06b1487112b33923b --region us-east-1

AWS Monitoring
All production alerts go to gaslan@troxy.io. Managed via Terraform — do not create alarms manually in the console.
Important — SNS subscription

gaslan@troxy.io must confirm the AWS SNS subscription email to receive CloudWatch alerts. Subject: "AWS Notification - Subscription Confirmation". Click the link in that email once.

AWS Budget

SettingValue
Budget nametroxy-mvp-monthly
Monthly limit$50 USD
Alert threshold80% of actual spend (~$40)
Alert emailgaslan@troxy.io
Terraform sourcemvp/us-east-1/budgets/terragrunt.hcl

CloudWatch Alarms

All alarms publish to the troxy-mvp-ops-alerts SNS topic → email to gaslan@troxy.io. Terraform source: mvp/us-east-1/monitoring/terragrunt.hcl.

AlarmTriggerWhat it means
troxy-mvp-lambda-errors≥5 errors in 5 minLambda crashing — check CloudWatch logs immediately
troxy-mvp-lambda-throttlesAny throttleLambda concurrency limit hit — requests are being dropped
troxy-mvp-lambda-duration-p99P99 > 8,000ms for 2 periodsGetting close to the 15s Lambda timeout — slow DB or cold starts
troxy-mvp-rds-cpuCPU > 80% for 10 minDB under load — check for missing indexes or runaway queries
troxy-mvp-rds-storageFree storage < 2GBDisk filling up — audit_log table growing, consider archiving
troxy-mvp-rds-connectionsConnections > 80Connection pool exhausted — Lambda concurrency too high for db.t4g.micro
troxy-mvp-apigw-5xx≥5 server errors in 5 minAPI crashing at the gateway level — Lambda may not be starting
troxy-mvp-apigw-4xx≥50 client errors in 5 minSpike in auth failures — possible abuse or broken client

How to check alarms manually

# List all alarms and their current state
aws cloudwatch describe-alarms --alarm-name-prefix "troxy-mvp" \
  --query 'MetricAlarms[*].[AlarmName,StateValue]' \
  --output table

# Check Lambda errors in the last hour
aws logs filter-log-events \
  --log-group-name "/aws/lambda/troxy-mvp-core-handler" \
  --start-time $(date -v-1H +%s000) \
  --filter-pattern "ERROR"

# Check current month AWS spend
aws ce get-cost-and-usage \
  --time-period Start=$(date +%Y-%m-01),End=$(date +%Y-%m-%d) \
  --granularity MONTHLY \
  --metrics BlendedCost \
  --query 'ResultsByTime[0].Total.BlendedCost.Amount' \
  --output text
To change alert email or thresholds

Edit mvp/us-east-1/monitoring/terragrunt.hcl or mvp/us-east-1/budgets/terragrunt.hcl in troxy-tf-live, commit, and push. GitHub Actions applies automatically. Never touch alarms in the AWS console.