DEV Community

Cover image for Controlling AI API Spend in a Next.js 15 Micro-SaaS with Cordis
power zhong
power zhong

Posted on

Controlling AI API Spend in a Next.js 15 Micro-SaaS with Cordis

Controlling AI API Spend in a Next.js 15 Micro-SaaS with Cordis

At 3:17 AM on a Sunday, your credit card gets charged $1,400 because a mobile user tapped "Generate" four times on a flaky cellular connection. The browser timed out and retried; your serverless handler caught each severed TCP socket and spawned another upstream call; and an unthrottled worker hammered the model provider until your monthly quota collapsed into a wall of 429 errors.

Solo micro-SaaS projects rarely fail because a single AI inference call is too expensive. They fail because the system lacks a hardened boundary separating user intent from orchestration, retries, and ledger accounting.

Before adding another model or tweaking system prompts, you must make AI execution observable, cacheable, and budget-constrained—without leaking billing logic into UI components.

The Cordis Boundary: Spatiotemporal Orchestration

Cordis (cordiverse/cordis) positions itself as a "Meta-Framework of Spatiotemporal Composability." However, inspecting the repository reveals a critical operational caveat: upstream documentation explicitly warns that the core APIs remain in active development and may change without notice [1].

Treating Cordis as an unvetted, drop-in replacement for a mature background queue or financial ledger is an unnecessary operational risk. Instead, treat Cordis as an internal orchestration boundary isolated behind a strict application adapter.

The Four-Tier Architecture

A production-ready AI request path requires four distinct operational tiers:

  1. Next.js 15 Route Handler

    Validates authentication, enforces payload boundaries, and performs upfront quota admission checks.

  2. Application Service

    Translates business domain operations (such as summarize_document) into model parameters. The frontend must never select model providers, configure temperature, or touch pricing tiers.

  3. Cordis Orchestration Boundary

    Manages temporal execution semantics: deduplication, in-flight request coalescing, circuit breaking, and clean cancellation. The application consumes a stable run() contract rather than raw framework internals.

  4. AI Gateway and Accounting

    Routes upstream requests, enforces edge caching, records audit logs, and returns normalized token telemetry.

Separate product intent from model execution. When you intertwine billing checks with route controllers, every pricing adjustment or provider failover requires an emergency application deploy.

The Cordis repository is a TypeScript monorepo configured with Yarn 4.14.1, esbuild, and Vitest [2]. While fully compatible with modern TypeScript applications at the package boundary, keep the framework isolated within a narrow adapter layer.

A Hardened Cost Guard

The following Next.js 15 route handler enforces deterministic admission control, hard payload ceilings, and execution isolation:

// app/api/summarize/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { createHash } from 'node:crypto'
import { runSummarization } from '@/server/ai/orchestrator'
import { getMonthlyUsage } from '@/server/billing/usage'

const MAX_INPUT_CHARS = 24_000
const MAX_OUTPUT_TOKENS = 900
const MONTHLY_TOKEN_LIMIT = 120_000

export async function POST(request: NextRequest) {
  const userId = request.headers.get('x-user-id')
  if (!userId) {
    return NextResponse.json({ error: 'unauthorized' }, { status: 401 })
  }

  const body = await request.json().catch(() => null)
  const document = typeof body?.document === 'string' ? body.document : ''

  if (!document || document.length > MAX_INPUT_CHARS) {
    return NextResponse.json(
      { error: 'document must be between 1 and 24000 characters' },
      { status: 400 },
    )
  }

  const usage = await getMonthlyUsage(userId)
  if (usage.tokens >= MONTHLY_TOKEN_LIMIT) {
    return NextResponse.json(
      { error: 'monthly AI budget exhausted' },
      { status: 429 },
    )
  }

  const requestKey = createHash('sha256')
    .update(`${userId}:${document}`)
    .digest('hex')

  const result = await runSummarization({
    requestKey,
    userId,
    document,
    maxOutputTokens: MAX_OUTPUT_TOKENS,
    cacheTtlSeconds: 86_400,
  })

  return NextResponse.json({
    summary: result.text,
    usage: {
      inputTokens: result.inputTokens,
      outputTokens: result.outputTokens,
      cached: result.cached,
      route: result.route,
    },
  })
}
Enter fullscreen mode Exit fullscreen mode

The runSummarization adapter is the only component aware of the underlying orchestration engine. Its interface enforces idempotency and cancellation tokens.

Never treat retries as free. If an upstream provider accepted the prompt but the connection dropped before streaming concluded, a blind retry doubles your invoice. Furthermore, the deterministic cache key must incorporate every parameter affecting the generation: prompt versions, output tokens, and locale. Hashing only the document body causes prompt updates to fail to reflect while serving stale cache hits.

Production Reality: What Tutorials Hide

Toy tutorials showcase the happy path of a single successful request. Production infrastructure must survive real-world operational failure modes:

  • Aggressive Client Retries: Mobile networks resend timed-out requests, triggering duplicate billable invocations.
  • Dangling Provider Work: Upstream providers continue generating and billing even after your server aborts the client socket.
  • Cache Drift: Modifying system prompts without cache invalidation silently serves outdated responses.
  • Asynchronous Billing Leaks: Measuring usage only after completing the response loses billing records if clients disconnect early. Durable reservations keyed by requestKey must precede execution.
  • Unbounded Payloads: Pasted PDFs and logs exhaust entire organizational token quotas in seconds.

Where B-Lost Fits

For an independent SaaS builder, building distributed ledger accounting and low-latency cache layers in-house drains core product focus. Routing requests through an intelligent edge gateway shifts token reconciliation, fallbacks, and caching away from application runtimes.

In reproducible benchmarks, routing inference traffic through B-Lost’s 0.8x pricing and prompt caching reduced monthly AI API expenses from $300+ down to $60 for an independent SaaS product. These metrics represent an empirical case study rather than a blanket forecast; actual savings depend on cache-hit ratios, output lengths, and retry topology.

The hardest operational dilemma in micro-SaaS is execution ownership: do you enforce token idempotency and circuit breaking inside stateful in-process workers, or push orchestration out to an external proxy layer?

What does your team's gateway topology look like under load? Are you running in-process orchestration adapters or external edge proxies to catch runaway retries? Drop your architecture and battle scars in the comments below.

Disclosure: Compute infrastructure and multi-model benchmark relays for this writeup are sponsored by b-lost.com — an enterprise AI gateway offering 0.8x official pricing, native prompt caching, and zero user-data retention. All benchmark metrics reflect independent reproducible testing.

Sources

[1] Cordis core README

[2] Cordis package.json

Top comments (0)