← Blog

How to Use an API Gateway: A Developer's Guide

2026-09-07 · 5 min read · SubToAPI Team

An API gateway sits between your application and one or more backend services, handling authentication, routing, rate limiting, and response shaping in one place. Using one means changing how your client code makes requests: instead of calling each backend directly, you send every request to the gateway's URL with an API key, and the gateway forwards it, enforces limits, and returns a normalized response.

This guide walks through the practical steps of using a gateway once it's already set up — how to authenticate, structure requests, handle streaming and errors, and avoid the mistakes that cause most integration bugs. If you're deciding whether to build or adopt one, that's a separate question; here we assume you already have a gateway endpoint and a key, and you need to write client code against it.

Step 1: Get Your API Key and Base URL

Every gateway request needs two things: a base URL and a credential. The credential is usually an API key passed as a bearer token, not a query parameter — query parameters leak into logs and browser history.

curl https://api.example.com/v1/resource \
  -H "Authorization: Bearer $API_KEY"

Store the key in an environment variable, never in source code. If you're using SubToAPI to expose Claude access as an HTTPS API, you generate a key in the dashboard (sub_live_...) after signing up at /signup, and every request goes to https://api.subtoapi.app/v1/... with that key in the Authorization header. The quickstart covers the exact first request end to end.

Step 2: Understand the Routing Model

A gateway maps incoming paths to backend services. You don't need to know the backend topology — you just need to know the paths the gateway exposes. Check the docs for the resource paths rather than guessing based on the backend's original API.

For a messages-style API, that typically looks like:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "Summarize this PR description in two sentences."}
    ]
  }'

See /docs/messages for the full request and response schema.

Step 3: Handle Rate Limits and Retries

Gateways enforce limits per key, per plan, or per endpoint. When you exceed one, you'll get a 429 response, usually with a Retry-After header. Build retry logic into your client from the start:

async function callGateway(payload, retries = 3) {
  const res = await fetch("https://api.subtoapi.app/v1/messages", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(payload)
  });

  if (res.status === 429 && retries > 0) {
    const wait = Number(res.headers.get("retry-after") || 2) * 1000;
    await new Promise(r => setTimeout(r, wait));
    return callGateway(payload, retries - 1);
  }

  if (!res.ok) throw new Error(`Gateway error: ${res.status}`);
  return res.json();
}

Exponential backoff is safer for production, but even a fixed delay with a retry cap prevents most transient failures from becoming outages.

Step 4: Use Streaming for Long-Running Responses

If the underlying service returns output incrementally — chat completions, transcriptions, generated text — the gateway should support server-sent events or chunked responses so your client doesn't wait for the entire payload. Set "stream": true in the request body and read the response as a stream of events rather than a single JSON blob:

const res = await fetch("https://api.subtoapi.app/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    model: "claude-sonnet-4-5",
    max_tokens: 1024,
    stream: true,
    messages: [{ role: "user", content: "Write a short changelog entry." }]
  })
});

const reader = res.body.getReader();
const decoder = new TextDecoder();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  process.stdout.write(decoder.decode(value));
}

Details on event formats and parsing are in /docs/streaming.

Step 5: Call Tools Through the Gateway

If the backend supports function or tool calling, the gateway passes tool definitions through and returns structured tool-use blocks instead of plain text. You define the tool schema in your request and inspect the response for a tool call before executing it and sending the result back:

{
  "model": "claude-sonnet-4-5",
  "max_tokens": 1024,
  "tools": [
    {
      "name": "get_weather",
      "description": "Get current weather for a city",
      "input_schema": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      }
    }
  ],
  "messages": [{ "role": "user", "content": "What's the weather in Lisbon?" }]
}

The response includes a tool_use block with the tool name and structured input. Your code executes the actual function, then sends the result back in a follow-up message. Full examples are in /docs/tools.

Step 6: Monitor Usage and Errors

Most gateways return usage metadata (tokens, request counts, latency) either in response headers or in the body. Log this from day one — it's how you catch a runaway integration before it hits a plan limit or generates an unexpected bill. If you're on a team plan, check whether usage is reported per key so you can attribute cost to the right service or teammate rather than debugging a shared total.

Common Mistakes to Avoid

Questions

Do I need to change my client code to switch API gateways? Yes, usually — the base URL, auth header format, and possibly the request schema will differ. Keep gateway calls behind a thin wrapper function so switching providers means editing one file, not your whole codebase.

Can I use an API gateway without an SDK? Yes. Gateways expose plain HTTPS endpoints, so curl, fetch, or any HTTP client works. SDKs are convenience wrappers, not a requirement.

What's the fastest way to test a gateway before integrating it into an app? Send a single request with curl and check the response shape, status codes, and headers (especially rate-limit and usage headers) before writing any client code. A five-minute manual test catches most integration surprises early.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →