Zuplo logo
Back to all articles
API Management

How to Route API Requests to Different Backends

Martyn Davies
February 2, 2026
4 min read

Learn how to implement Stripe-style environment-based routing using API key metadata to direct requests to sandbox or production backends through a single API endpoint.

If you've ever used Stripe's API, you've experienced a clever pattern: test keys and live keys both hit the same API endpoint, but they route to completely different backends. Your sandbox requests never touch production data, and you don't need to remember separate URLs for each environment.

It's called environment-based routing, and in this post we're going to show you how to implement it using TypeScript and the awesome programmable aspects of the Zuplo API Gateway.

Use this approach if you're:
  • Building an API with separate sandbox and production environments
  • Need to route customers to isolated backends for compliance or data residency
  • Want a single API endpoint that serves both shared and dedicated infrastructure
  • Looking to implement Stripe-style test/live key patterns

What is Environment-Based Routing?

Environment-based routing lets you direct API requests to different backend systems based on metadata attached to the caller's identity. Instead of exposing separate endpoints for sandbox vs. production (or different customer environments), you expose a single API URL. The gateway reads the caller's API key metadata or JWT claims and routes the request to the appropriate backend.

This creates a cleaner developer experience. Your API consumers don't need to manage multiple base URLs or remember which environment they're targeting. The key itself carries that context.

Why Use Environment-Based Routing?

There are three common scenarios where this pattern makes sense to use:

Sandbox/Production Separation

The Stripe model. Give developers a test key for development and a live key for production. Both keys work against your single API endpoint, but test keys route to sandbox infrastructure with mock data, while live keys route to production systems with real data. Developers can safely test integrations without worrying about affecting production.

Customer Isolation

For B2B APIs with compliance or data residency requirements, you might need to route each customer to their own isolated backend. A healthcare API might route Customer A's requests to their dedicated HIPAA-compliant infrastructure while Customer B routes to a separate isolated environment. The API surface looks identical; only the underlying backend differs.

Hybrid Multi-Tenant Architecture

Maybe most of your customers share a multi-tenant backend, but your enterprise customers pay for dedicated infrastructure. Environment-based routing lets you handle both cases through the same API endpoint. Standard customers route to shared infrastructure; premium customers route to their dedicated environment.

How Zuplo Implements This

Zuplo's programmable gateway makes this straightforward. When a request is authenticated (via API key or JWT), user information becomes available on request.user. This includes metadata you've attached to the API key or custom claims from the JWT.

A custom inbound policy reads this metadata and sets the backend URL dynamically:

TypeScripttypescript
import { ZuploContext, ZuploRequest, environment } from "@zuplo/runtime";

export default async function policy(
  request: ZuploRequest,
  context: ZuploContext,
) {
  const userEnvironment = request.user?.data?.environment;

  if (userEnvironment === "sandbox") {
    context.custom.downstreamUrl = environment.SANDBOX_BACKEND_URL;
  } else if (userEnvironment === "production") {
    context.custom.downstreamUrl = environment.PRODUCTION_BACKEND_URL;
  } else {
    throw new Error("Unknown environment in user data");
  }

  return request;
}

The URL Rewrite handler then uses context.custom.downstreamUrl to forward the request to the correct backend. The caller never sees which backend handled their request; they just get the appropriate response.

To set this up, you attach metadata to your API keys when creating them. You can do this in the Zuplo portal for testing, or programmatically via the Zuplo API when provisioning keys for your users:

JSONjson
{
  "environment": "sandbox"
}

Or for production keys:

JSONjson
{
  "environment": "production"
}

The same pattern works with JWT authentication. Just include the environment (or customer ID, or tenant info) as a custom claim, and your routing policy reads it from request.user.data.

Benefits

This approach gives you a single entry point for all your customers. Documentation, SDKs, and client implementations stay simple because there's one URL to remember.

Policy enforcement happens uniformly at the gateway. Authentication, rate limiting, and other policies apply consistently before requests reach any backend. This ensures security and compliance across all environments without duplicating configuration.

And because Zuplo policies are just TypeScript, you can implement whatever routing logic you need: geographic routing, A/B testing, failover handling, or combinations of multiple factors.

Try It Yourself

We've published a complete working example that implements Stripe-style environment routing. The example includes mock backends, pre-configured policies, and step-by-step instructions for creating API keys with environment metadata.

Try it yourself

Environment-Based Routing Example

A complete working example that implements Stripe-style environment routing with API key metadata. Run locally or deploy directly to your Zuplo account.

Deploy

For the full implementation guide covering additional patterns like customer-specific routing and hybrid multi-tenant architectures, see our documentation.