NeoMoat Hub-Spoke Architecture

The Agency Spend Problem
Is an Approval Problem

SpendApproval eliminates the $22B annual programmatic waste[1] from delayed, lost, and unauthorized media spend decisions across agencies, clients, and platforms.

0s
Median approval latency
0%
Decision audit coverage
0
Escalation channels

Why Agencies Hemorrhage Budget

Every hour a spend approval sits in someone's inbox, the campaign loses pacing, the client loses trust, and the agency loses margin.

Approval Bottlenecks
Average creative review takes 8 days and 3+ revision cycles.[2] Senior stakeholders are in meetings, on planes, or across time zones. Campaigns miss their launch windows.
Zero Audit Trail
Approvals happen in email threads, Slack DMs, and verbal hallway conversations. When a client disputes a charge, there's no immutable proof of authorization.
Unauthorized Spend
Media buyers push campaigns live without proper sign-off. Only $0.36 of every programmatic dollar reaches a consumer — the rest is lost to intermediaries and low-quality inventory.[3]
Escalation Chaos
No systematic escalation when an approver is unavailable. The backup doesn't know they're the backup. Critical deadlines pass silently.
Cross-Platform Blindness
Google Ads, Meta, TikTok, DV360 — each has its own budget controls. No unified view of total client spend commitments across platforms.
Compliance Exposure
SOC 2 Trust Services Criteria require documented authorization controls for financial commitments.[4] Manual processes create gaps that auditors flag every quarter.

From Request to Receipt in Seconds

Every approval follows an automated, audited, enforceable path — with multi-channel escalation if the approver doesn't respond.

01
Request Created
API + Signed Token
02
Email Sent
One-Click Approve Link
03
Escalation Begins
Automatic Timer
04
SMS / Phone
Keypad Approval
05
Decision Made
Web / Phone / Timeout
06
Receipt Sealed
Hashed + Sealed
07
Enforcement
Pause / Reduce / Notify
08
Hub Notified
Event Stream

Every Angle Covered

SpendApproval is purpose-built for the agency media buying workflow, addressing every pain point with verifiable, auditable technology.

Security
Cryptographically Signed Approval Links
Every approval link is cryptographically signed with a rotating key. Tokens encode the request ID and expiry — they cannot be forged, reused, or tampered with.
Crypto EngineToken SigningRotating Keys
Audit
Immutable Receipt Chain
Every approval, rejection, escalation, and enforcement action generates a cryptographically hashed receipt stored across redundant layers. Integrity is verified on every read.
Hash VerificationArtifact StorageIntegrity Check
Speed
Multi-Channel Escalation
Email, SMS, Slack, and phone calls — with configurable chains per agency/client pair. Quiet hours respected. Automatic step advancement on timeout.
Stateful CoordinationTimer EngineTelephony
Speed
One-Touch Phone Approvals
Approvers can approve or reject by pressing 1 or 2 on their phone during an automated call. No app required, no login needed — works from any phone on Earth.
TelephonyPhone CallbackSecure Webhook
Infrastructure
Guaranteed Event Delivery
State changes and events are written atomically in a single transaction. A publisher drains events to a reliable stream — guaranteeing exactly-once delivery.
Atomic WritesEvent StreamOutbox Pattern
Infrastructure
Global Edge Architecture
Runs entirely on global edge compute — distributed across 300+ locations,[5] serverless, no cold starts. Stateful singletons provide dedicated coordination for each approval.
Edge ComputeStateful SingletonsSQL DatabaseObject StorageJob Queues
Security
Military-Grade Field Encryption
Sensitive fields are encrypted at rest with AES-256-GCM using native cryptography. Encryption keys are managed via a dedicated secret vault — never hardcoded.
Encryption at RestSecret VaultZero Trust
Integration
Hub-Spoke Event Streaming
Each agency spoke publishes events to the NeoMoat hub via a reliable event stream. The hub aggregates cross-agency reporting, enforces global policies, and detects drift.
Event BusEvent EnvelopeSigned Events
Audit
Full Admin Dashboard
Real-time stats, request/decision tables with filters, escalation policy management, communication logs, and receipt viewer — all behind zero-trust access controls.
Modern UIReal-Time DataSession Analytics
Integration
Platform Enforcement Actions
On rejection or timeout, automatically pause campaigns, reduce budgets, or notify stakeholders. Enforcement receipts are sealed and immutable.
Async ProcessingIdempotentRollback
Security
Zero-Trust Access + Single Sign-On
Admin panel protected by zero-trust JWT verification at the edge. API endpoints use session cookies with cryptographic signing. Hub uses SSO for cross-spoke auth.
Zero TrustJWTSession Cookies
Audit
Session Analytics & Replay
Full session recordings and event tracking across both the approval UI and admin dashboard. Understand exactly how approvers interact with requests.
Analytics EngineSession ReplayEvent Tracking

Edge-Native, Zero Trust, Fully Auditable

Every component runs on a global edge network. No origin servers, no VMs, no cold starts.

Approval UI
app.spendapproval.com
Admin Panel
admin.spendapproval.com
NeoMoat Hub
neomoat.com
API Gateway
Routes + Auth + CORS
Approval Engine
Lifecycle + Expiry
Escalation Engine
Chain + Quiet Hours
Notifier
Email / SMS / Phone
Executor
Enforce Actions
Publisher
Outbox → Events
Poller
Expiry + Reminders
SQL Database
8 tables, enforced
Object Storage
Immutable Receipts
Job Queue
Task Dispatch
Email Automation
Templated Delivery
Voice & SMS Engine
DTMF + Callbacks
Real-Time Event Stream
Replay-Capable

Complete System Workflow

A detailed technical walkthrough of every path through the system — from request creation to hub notification.

═══════════════════════════════════════════════════════════════════════════════════ PHASE 1 — REQUEST CREATION ═══════════════════════════════════════════════════════════════════════════════════ [ Client / Media Buyer ] │ ▼ POST /approval-requests ├── agency_id, client_id, platform, campaign_id ├── amount (minor units), currency, description ├── approver_email, metadata, expiry (default: 24h) │ ▼ ┌─────────────────────────────────────┐ │ ATOMIC DATABASE TRANSACTION │ └─────────────────────────────────────┘ ├── INSERT approval_requests (status: pending) ├── Generate HMAC-SHA256 signed token (encodes request_id + expiry) ├── INSERT outbox event: approval.requested │ ▼ ┌─────────────────────────────────────┐ │ STATEFUL SINGLETON INIT │ └─────────────────────────────────────┘ ├── Approval Coordinator │ ├── State: pending, expiry alarm set │ └── Single source of coordination (no race conditions) ├── Escalation Coordinator │ ├── Load policy for (agency_id, client_id) │ ├── If no policy → default chain: [email, 1hr timeout] │ └── Parse quiet hours config │ ▼ Enqueue initial notification job → Job Queue │ ▼ Return 201: { id, approval_url, expires_at } ═══════════════════════════════════════════════════════════════════════════════════ PHASE 2 — NOTIFICATION DELIVERY ═══════════════════════════════════════════════════════════════════════════════════ [ Job Queue ] ──▶ Notifier Worker │ ├── channel = email? │ ├── Send via Email Automation provider │ ├── HTML template with one-click approve/reject links │ ├── Record: communication_attempts (sent/failed) │ └── Write outbox: escalation.step_sent │ ├── channel = sms? │ ├── Send via Voice & SMS Engine │ ├── Short message with approval instructions │ ├── Record: communication_attempts │ └── Write outbox: escalation.step_sent │ ├── channel = phone? │ ├── Send SMS with call-back DID number │ ├── "Press 1 to approve, 2 to reject" │ ├── Create call_session (status: initiated) │ ├── Record: communication_attempts │ └── Write outbox: escalation.step_sent │ └── channel = slack? ├── Post to designated channel/user └── Record: communication_attempts ═══════════════════════════════════════════════════════════════════════════════════ PHASE 3 — DECISION PATHS ═══════════════════════════════════════════════════════════════════════════════════ ┌─────────────────────────────────────────────────────────────────┐ │ THREE DECISION PATHS │ └─────────────────────────────────────────────────────────────────┘ PATH A: WEB APPROVAL/REJECTION ───────────────────────────────── [ Approver clicks link ] │ ▼ GET /approve/{token} ├── Validate HMAC signature + expiry ├── If invalid → 400 error └── If valid → redirect to approval UI │ ▼ [ Approver reviews details ] ├── Amount, campaign, platform, description └── Clicks Approve or Reject │ ▼ POST /approve/{token} or POST /reject/{token} ├── Re-validate token ├── Check status == 'pending' (else 409 conflict) │ ▼ ┌─────────────────────────────────────┐ │ ATOMIC DECISION TRANSACTION │ └─────────────────────────────────────┘ ├── UPDATE approval_requests → status: approved/rejected ├── INSERT approval_decisions (method: web, IP, user_agent) ├── Generate receipt → SHA-256 hash of payload ├── INSERT immutable_receipts ├── INSERT outbox: approval.decided └── Store receipt copy → Object Storage (non-blocking) │ ▼ Notify coordinators → cancel escalation, delete alarms PATH B: PHONE (DTMF) APPROVAL/REJECTION ────────────────────────────────────────── [ Approver calls DID number ] │ ▼ Approver presses: 1 = Approve | 2 = Reject │ ▼ POST /telephony/dtmf-callback ├── Validate callback secret header ├── Map DTMF digit → decision ├── Check status == 'pending' │ ▼ ┌─────────────────────────────────────┐ │ ATOMIC DECISION TRANSACTION │ └─────────────────────────────────────┘ ├── UPDATE approval_requests → status: approved/rejected ├── INSERT approval_decisions (method: dtmf, digit, call_id) ├── Generate receipt → SHA-256 hash (includes DTMF context) ├── INSERT immutable_receipts ├── INSERT outbox: approval.decided ├── UPDATE call_sessions → dtmf_received └── Store receipt copy → Object Storage │ ▼ Notify coordinators → cancel escalation, delete alarms PATH C: EXPIRY (NO RESPONSE) ────────────────────────────── [ Approval Coordinator alarm fires ] │ ▼ Status still 'pending'? ├── YES → │ ├── UPDATE approval_requests → status: expired │ ├── INSERT outbox: approval.expired │ └── Notify Escalation Coordinator → cancel │ └── NO → Already decided, no-op [ Poller Worker ] (runs every 5 min — safety net) ├── SELECT pending requests WHERE expires_at <= now ├── Expire any that the coordinator missed └── Send 15-min expiry reminder emails ═══════════════════════════════════════════════════════════════════════════════════ PHASE 4 — ESCALATION ENGINE ═══════════════════════════════════════════════════════════════════════════════════ [ Escalation Coordinator ] │ ▼ ┌──────────────────────────────────────────────────────┐ │ ESCALATION CHAIN (configurable per agency/client) │ │ │ │ Step 0: Email[email protected] (timeout: 1hr) │ │ │ │ │ ▼ (no response after timeout) │ │ Step 1: SMS → +1-555-0100 (timeout: 30m) │ │ │ │ │ ▼ (no response after timeout) │ │ Step 2: Phone → +1-555-0100 (timeout: 15m) │ │ │ │ │ ▼ (no response / max attempts) │ │ Step 3: Email[email protected] (timeout: 1hr) │ │ │ │ │ ▼ (all steps exhausted) │ │ Generate escalation receipt → STOP │ └──────────────────────────────────────────────────────┘ QUIET HOURS LOGIC: ├── Each step checks: is current time in quiet hours? ├── If YES → defer alarm to end of quiet hours ├── Timezone-aware (per agency/client config) └── Day-of-week filtering supported PHONE ATTEMPT LIMITS: ├── max_call_attempts per policy (default: 2) ├── If limit reached → skip to next step └── Each attempt tracked in call_sessions table ═══════════════════════════════════════════════════════════════════════════════════ PHASE 5 — ENFORCEMENT ═══════════════════════════════════════════════════════════════════════════════════ [ Decision Made ] │ ├── Approved → No enforcement needed │ ├── Rejected → │ ├── Enqueue enforcement job │ └── action_type: pause_campaign / reduce_budget / notify_only │ └── Expired → ├── Enqueue enforcement job └── action_type: pause_campaign (default) │ ▼ [ Executor Worker ] ├── Idempotency check (skip if already applied) ├── Execute platform action ├── Record: enforcement_actions (status: applied/failed) ├── Generate enforcement receipt → SHA-256 hash ├── INSERT immutable_receipts ├── INSERT outbox: enforcement.applied / enforcement.failed └── Store receipt → Object Storage ROLLBACK: ├── If enforcement fails → status: failed, reason logged ├── Manual rollback supported → status: rolled_back └── Each state transition receipted ═══════════════════════════════════════════════════════════════════════════════════ PHASE 6 — RECEIPT INTEGRITY & COMPLIANCE ═══════════════════════════════════════════════════════════════════════════════════ RECEIPT GENERATION (triggered at every decision point): ┌─────────────────────────────────────────────────┐ │ Receipt Types: │ │ ├── approval (web approve/reject) │ │ ├── rejection (web approve/reject) │ │ ├── enforcement (pause/reduce/notify) │ │ └── escalation (chain exhausted/cancelled) │ │ │ │ Each Receipt Contains: │ │ ├── Unique ID (UUID) │ │ ├── Full decision payload (JSON) │ │ ├── SHA-256 hash of payload │ │ ├── Timestamp, actor, method, IP, user-agent │ │ └── Dual-stored: SQL database + Object Storage │ └─────────────────────────────────────────────────┘ INTEGRITY VERIFICATION (on every read): ├── Fetch receipt from SQL database ├── Fetch copy from Object Storage ├── Recompute SHA-256 hash from payload ├── Compare with stored hash ├── If mismatch → TAMPER DETECTED → flag immediately └── Return: integrity_valid (true/false) ═══════════════════════════════════════════════════════════════════════════════════ PHASE 7 — OUTBOX & EVENT PUBLISHING ═══════════════════════════════════════════════════════════════════════════════════ TRANSACTIONAL OUTBOX PATTERN: [ Any State Change ] │ ├── Business logic + outbox INSERT in same transaction │ (zero events lost, zero double-publishes) │ ▼ [ outbox table ] ├── event_type, payload_json, correlation_id ├── status: pending → sent | failed ├── attempts: 0 → max 5 └── last_attempt_at (lease mechanism) │ ▼ [ Publisher Worker ] (cron: every 60s) ├── SELECT pending entries (batch of 50) ├── Atomic claim via lease timestamp ├── Connect to Event Stream (WebSocket) ├── Build envelope: { event_id, event_type, spoke_id, correlation_id, payload } ├── Publish to stream ├── On success → mark 'sent' ├── On failure → retry (up to 5 attempts) └── Hub deduplicates on event_id EVENT TYPES PUBLISHED: ├── approval.requested.v1 ├── approval.decided.v1 ├── approval.expired.v1 ├── escalation.step_sent.v1 ├── escalation.step_failed.v1 ├── enforcement.applied.v1 └── enforcement.failed.v1 ═══════════════════════════════════════════════════════════════════════════════════ PHASE 8 — HUB CONSUMPTION & CROSS-AGENCY GOVERNANCE ═══════════════════════════════════════════════════════════════════════════════════ [ Event Stream ] ──▶ [ NeoMoat Hub ] │ ├── Deduplicate on event_id ├── Aggregate cross-agency reporting ├── Enforce global policies ├── Detect drift (approved vs. actual spend) └── Replay-capable: rebuild state from event history SPOKE ISOLATION: ├── Each agency spoke operates independently ├── Hub sees events but NOT raw spend data ├── Cryptographically authenticated event envelopes └── Zero-trust federation between spokes ═══════════════════════════════════════════════════════════════════════════════════ DATABASE SCHEMA (8 TABLES) ═══════════════════════════════════════════════════════════════════════════════════ approval_requests Primary request record (status state machine) approval_decisions Who decided, when, how (web/dtmf/timeout) escalation_policies Per agency/client chain + quiet hours config communication_attempts Every notification: channel, status, error detail call_sessions Phone call tracking: DTMF digits, call status immutable_receipts Cryptographic receipts with hash verification enforcement_actions Platform actions: pause/reduce/notify + rollback outbox Transactional event queue (at-least-once delivery)

15 Roles. Real Problems. One Solution.

These personas are fictional composites built from industry research,[9] agency interviews,[10] and real-world pain points[11] across the media buying chain. They represent the roles, frustrations, and needs that advertising professionals and their clients face every day.

Why This Hasn't Been Built Before

SpendApproval combines capabilities that didn't exist together until modern edge compute primitives matured. Here's what makes it unprecedented.

Stateful Singleton Coordination
Each approval request gets its own globally-unique stateful compute instance with timer-based expiry. No distributed locks, no race conditions, no external state stores.
GAME-CHANGER: Eliminates entire categories of concurrency bugs
Cryptographic Receipt Sealing
Every decision produces a cryptographically hashed, dual-stored immutable receipt. On read, the hash is recomputed and verified — any tampering is immediately detected.
GAME-CHANGER: Audit-grade proof that stands up in disputes
Phone-to-Decision Pipeline
A phone call where pressing a button on the keypad cryptographically signs a financial approval decision. The phone callback chain is webhook-verified and produces the same immutable receipt as a web approval.
GAME-CHANGER: Reach approvers with no internet access
Transactional Outbox Pattern
State mutations and event publishing are atomic in a single database batch. A separate publisher drains to a reliable event stream with retry + dead-letter semantics. Zero events lost, zero double-publishes.
GAME-CHANGER: Event-driven architecture with zero message loss
Quiet-Hours-Aware Escalation
Escalation chains respect configurable quiet hours per agency/client. If a step would fire at 2am, it defers to the start of business hours — but urgent channels still escalate immediately.
GAME-CHANGER: Humane automation that respects human schedules
Hub-Spoke Zero-Trust Federation
Each agency spoke is independently deployed but federated through the NeoMoat hub via cryptographically authenticated events. The hub enforces cross-agency policies without access to raw spend data.
GAME-CHANGER: Multi-tenant isolation with centralized governance

Every Dollar Approved.
Every Decision Sealed.

Explore the interactive demo — real UI, real workflows, sample data. See how approvals, escalations, and immutable receipts work end to end.

Launch Agency Demo Check API Health

References

  1. ANA (Association of National Advertisers), "Programmatic Media Supply Chain Transparency Study," Dec 2023. The $88B open web programmatic ecosystem contains an estimated $22B in waste — including $10B on made-for-advertising sites. Only $0.36 of every dollar entering a DSP effectively reaches a consumer. ana.net
  2. Ziflow, "From Chaos to Compliance: Creative Marketing Survey," 2023. Nearly 4 in 5 respondents encounter regular issues receiving feedback on creative projects; more than half lack a consistent review and approval process. ziflow.com
  3. MarTech, "ANA Study Finds 25% of Programmatic Ad Dollars Are Wasted," 2023. Reports that only $0.36 of every programmatic dollar reaches a consumer; ~$0.29 goes to ad-tech fees and ~$0.35 to low-quality inventory. Made-for-advertising supply grew from ~5% to nearly 30% of web auctions between 2020 and 2023. martech.org
  4. AICPA & CIMA, "SOC 2 — Trust Services Criteria," 2022 revision. Establishes criteria for Security, Availability, Processing Integrity, Confidentiality, and Privacy controls at service organizations, including authorization requirements for financial transactions. aicpa-cima.com
  5. Cloudflare, "Cloudflare's Global Network Grows to 300 Cities," June 2023. Data centers in 330+ cities across 122+ countries, connected to 12,000+ networks, within 50ms of 95% of the world's Internet-connected population. blog.cloudflare.com
  6. ISBA / PwC, "Programmatic Supply Chain Transparency Study," 2020. Found that 15% of programmatic ad spend was entirely unattributable (the "unknown delta"), and only 12% of impressions could be matched end-to-end across the supply chain. isba.org.uk
  7. Insurance Journal, "Agency E&O Buyers Report Higher Premiums," Nov 2024. 73% of agencies saw E&O renewal premium increases in 2024, up from 63.5% in 2023; 69% expect further increases at next renewal. insurancejournal.com
  8. ANA / 4A's, "Client-Agency Relationship Tenure Report," Apr 2025. Media agency-client tenure averages just 3.7 years; trust and transparency cited as top factors. Clients without mandatory review periods maintain relationships for 8.1 years vs 3.8 years with frequent reviews. mediapost.com
  9. IAB (Interactive Advertising Bureau), "International Report on Programmatic In-Housing," 2020. Examines how programmatic is restructuring agency roles — 69% of advertisers still rely on external partners, while 33% of agencies run in-house trading desks. iab.com
  10. ANA, "Media Transparency Initiative," ongoing. Industry-wide effort documenting non-transparent business practices across media buying including rebates, undisclosed margins, and insufficient spend governance. ana.net
  11. Digiday, "Media Agency Report 2024: The State and Future of the Media Agency," 2024. Survey of agency professionals on client spending trends, operational challenges, and the impact of retail media fragmentation across 200+ networks. digiday.com