Architecture

The whole system on one page. Read top-to-bottom: where requests enter, what gates they cross, what gets logged, and what providers we sit on top of.


                  ┌────────────────────────────┐
                  │   Your Agent Code / LLM    │
                  │  (uses SDK or MCP tools)   │
                  └─────────────┬──────────────┘
                                │  Bearer ak_*
                                │  Idempotency-Key
                                │  x-correlation-id
                                ▼
            ┌───────────────────────────────────────┐
            │       Anima API (api.useanima.sh)     │
            │  ┌─────────────────────────────────┐  │
            │  │  Auth → Rate-limit → Versioning │  │
            │  │  Idempotency → Audit → Errors   │  │
            │  └─────────────────────────────────┘  │
            └────┬───────┬───────┬───────┬──────────┘
                 │       │       │       │
                 ▼       ▼       ▼       ▼
              ┌────┐ ┌────┐ ┌────┐  ┌────────┐
              │Mail│ │SMS │ │Vox │  │ Vault  │
              └─┬──┘ └─┬──┘ └─┬──┘  └───┬────┘
                │      │      │         │
                │      │      │         │
        ┌───────┘      │      └─────┐   │
        │              │            │   │
        ▼              ▼            ▼   ▼
   ┌─────────┐   ┌──────────┐  ┌──────────────┐
   │  AWS    │   │  Twilio  │  │ bw-serve +   │
   │  SES    │   │   /      │  │ Vaultwarden  │
   │         │   │  Telnyx  │  │ + envelope   │
   └─────────┘   └────┬─────┘  └──────────────┘
                      │
                      │ TCPA + RND + ToD + cap-check
                      ▼
                ┌─────────────────┐
                │  Outbound dial  │
                │  (server-side   │
                │   gates passed) │
                └─────────────────┘

   Cross-cuts (every domain):
     audit_events ← every action emits one row keyed by
                    correlation_id (workflow chain) +
                    request_id (per-call ID)
     hard-cap     ← MTD spend per meter checked before write;
                    block at 100% (or alert-only per setting)
     trust-score  ← signup gate: domain age / ASN / Stripe CVC

   Out-of-band:
     /v1/events/stream — SSE feed of every audit_events row,
                         consumed by 'am tail' and the dashboard
     /v1/audit/events  — REST query by correlation_id
     mcp.useanima.sh   — MCP server, 190+ tools across 6 domains

The API surface (api.useanima.sh)

One Fastify-based service handles every customer-facing API call. The middleware chain is fixed and runs in this order on every request:

  1. auth — resolves the ak_* / mk_* token to an org + agent.
  2. rate-limit — per-tier per-minute (Redis-backed sliding window) plus per-org per-second soft cap. X-RateLimit-* headers on every response.
  3. api-versioning — pins to v1; emits X-API-Version.
  4. idempotency — POST/PUT/PATCH/DELETE replay cache forIdempotency-Key retries.
  5. audit — every action emits a row to audit_events tagged with correlation_id.
  6. error-handler — RFC 7807 problem+json on failure.

See /api-reference for the wire contract.

Domain boundaries

Five domain modules behind the API surface:

  • Mail — outbound SES, inbound parsing, DKIM/DMARC config. Custom domains via the dashboard.
  • SMS — Twilio 10DLC + toll-free. Per-tier daily caps; opt-out keyword handling server-side.
  • Voice (Vox) — Telnyx PSTN dial pipeline behind TCPA + RND + time-of-day gates. Tier-based cap on per-day calls.
  • Vault — bw-serve + Vaultwarden under an encryption envelope. Server-side masking before responses leave the API.
  • Platform — admin, audit, billing, trust-score. Cross-cutting concerns.

Server-side safety gates

Three voice gates run before the dial:

  • TCPA — requires consent_source on every outbound call. Missing or malformed → 403.
  • RND — Twilio Lookup against the FCC Reassigned Numbers Database. 30-day Postgres cache. Reassigned numbers never dial.
  • Time-of-day — 8am–9pm local enforced from destination area code. Per-state stricter windows configurable.

Plus the cross-cutting hard cap with 80% / 90% / 100% notifications.

MCP surface (mcp.useanima.sh)

One URL, path-routed by domain. Same Postgres + provider stack as the REST API; a different protocol surface. 190+ tools across email, voice, vault, phone, platform, agent. anima_discover({intent}) for tool routing when the LLM doesn't know the exact name.

Audit chain (the data moat)

Every action emits one row to audit_events tagged with correlation_id (workflow ID) and request_id (per-call ID). Inbound email gets a synthetic correlation ID so reply chains link back to the trigger.

/audit renders the chain; /v1/events/stream feeds am tail via SSE.

What's NOT in this diagram

  • Consolidated MCP routing — Cloud Run service mcp-server consumes the same Anima API behind it.
  • Async workers (audit retention, baseline computation, anomaly detection, Stripe webhook ingest, auto-pay). They read/write the same Postgres but don't sit on the synchronous request path.
  • Console (dashboard.useanima.sh) — separate Next.js app, calls the same API via oRPC.
  • WebSocket bridge (used by the Chrome extension) — separate auth, separate channel; bypasses the REST middleware chain.