Fixing 403 Errors While Keeping AI Costs Low

January 20, 2026 · Abhishek Mukherjee

← Back to portfolio

While building my content generation app, the system was breaking with 403 and 429 errors, but the deeper issue wasn't just reliability. It was that my initial approach would never scale cheaply.

I'm intentionally trying to keep costs low while still building something production-ready. That constraint heavily influenced every technical decision I made during this phase.

The Problem

The app generates long-form content using a map-reduce style workflow. A single blog post can trigger 20 or more model calls in a short burst. On Gemini's free tier, this immediately caused 429 rate-limit errors. Requests were blocked mid-generation, leaving half-written content and failed jobs.

On top of that, some early calls were being made directly from the browser, which triggered 403 forbidden errors because providers correctly block client-side API usage to protect keys.

At that point, it was clear that I couldn't "patch" this. I needed to redesign how the app talks to AI providers.

Moving to a Multi-Provider Setup

Instead of relying on a single model or vendor, I moved to a multi-provider setup that lets me choose the cheapest and fastest option for each task. Groq became the primary engine for high-volume work like fact extraction and section-level writing. It's significantly faster for repetitive tasks and has a separate quota, which means I can generate content without constantly worrying about hitting limits or racking up costs.

I integrated Groq using the OpenAI SDK by pointing the base URL to Groq's endpoint. This let me reuse existing logic without locking myself into one provider. The performance improvement was immediate, and the system stopped timing out under load.

Still, speed alone isn't enough if the goal is reliability on a budget. That's where OpenRouter came in. I use it as a universal fallback layer. If Gemini or Groq fails for any reason, the system automatically routes the request through OpenRouter, which gives access to multiple models, including free and low-cost ones, under a single API key. This ensures the generation process doesn't stop halfway through just because one provider is unavailable or temporarily rate-limited.

Fixing the 403s on the Backend

To permanently fix the 403 errors, I moved all AI calls to the backend. Everything now runs through Next.js API routes and is orchestrated using Inngest. This hides API keys completely, satisfies provider security requirements, and eliminates browser-side failures.

More importantly, it lets me control execution properly instead of hoping the client behaves.

Inngest plays a key role here because long-form content generation isn't instant. If a provider hits a rate limit, the workflow pauses, waits a few seconds, and retries automatically. The user never sees an error, and I don't pay for failed runs that produce nothing.

Where Things Stand

Right now, I'm finishing the multi-provider-gateway.ts file, which acts as the traffic controller for the entire system. It decides which provider to use based on availability, cost, and task type.

← Back to portfolio