Problem Statement & Context
Corporate Card System — Problem Statement & Context
Problem Statement & Context
Corporate card platforms (Brex, Ramp, Stripe Issuing) sit between employers and card networks. You issue virtual or physical cards, enforce spend policies in milliseconds at authorization time, stream transactions to finance, and settle against company funding accounts. Unlike expense reports filed after the fact, the critical path is auth-time decisioning with network timeouts under 2 seconds and issuer SLAs targeting <100ms internal processing.
Personas
- Cardholder: swipe, see declines with reasons, attach memos post-auth
- Manager / Admin: set per-card limits, MCC blocks, vendor locks
- Finance: fund accounts, reconcile GL, chase out-of-policy spend
Scale anchors
Assume 42k tenants, 4.8M active cards, 95M authorizations/month, 1.4B settled volume/month. Lunch-hour peak 3.2× daily auth rate. Targets: auth decision p99 <85ms, card create API p99 <400ms, webhook delivery p99 <5s.
Core tension
authorization_id must be idempotent across network retries while card_id spend counters update atomically. You never store PAN—only issuer tokens and auth metadata.
1 def evaluate_spend(policy: dict, req: dict) -> dict: 2 if req["mcc"] in policy.get("blocked_mccs", []): 3 return {"approved": False, "code": "MCC_BLOCKED"} 4 if req["amount_cents"] + req["daily_spent"] > policy["daily_limit_cents"]: 5 return {"approved": False, "code": "LIMIT_DAILY"} 6 return {"approved": True, "code": "APPROVED"}
1 interface AuthWebhookPayload { 2 authorizationId: string; 3 cardId: string; 4 amountCents: number; 5 currency: string; 6 mcc: string; 7 decision: "approved" | "declined"; 8 declineCode?: string; 9 } 10 11 export async function postAuthWebhook( 12 tenantId: string, 13 payload: AuthWebhookPayload, 14 ): Promise<void> { 15 const body = JSON.stringify(payload); 16 const sig = signHmac(body, tenantSecrets.get(tenantId)); 17 await fetch(webhookUrl(tenantId), { 18 method: "POST", 19 headers: { "X-Signature": sig, "Idempotency-Key": payload.authorizationId }, 20 body, 21 }); 22 }
1 public final class AuthorizationService { 2 public AuthDecision decide(AuthRequest req, String idempotencyKey) { 3 return idempotencyStore.computeIfAbsent(idempotencyKey, k -> { 4 PolicySnapshot snap = policyCache.get(req.cardId(), req.policyVersion()); 5 AuthDecision d = ruleEngine.evaluate(req, snap); 6 ledger.appendHold(req, d); 7 audit.log(req, d, snap.id()); 8 return d; 9 }); 10 } 11 }
Section 1 focus
For design-corporate-card, Problem Statement & Context should emphasize authorization_id idempotency, policy_version at swipe time, and fail-closed declines—not post-hoc expense reports.
Why interviewers care
Corporate Card System interviews reward crisp scope, explicit trade-offs, and failure stories—not generic microservice diagrams.
Interview checkpoint
Name one failure story for Problem Statement & Context that proves you understand real outages, not happy-path diagrams.
Key Highlights
- •Problem Statement & Context: auth-time policy on card_id
- •Idempotent authorization_id across network retries
- •Issuer token boundary—never persist PAN
- •Phase understanding checkpoint for design-corporate-card
Section Rescue Kit
Buzzwords to use:
Safe statements:
- "We never store PAN—only issuer tokens and auth metadata."
- "If policy cache is stale beyond TTL, I fail closed to decline."