Home / Insights / Architecture and Modernization

Architecture and Modernization

Building APIs for AI Features: Streaming, Limits, Versioning and Safety

Putting a language model behind your own API changes the usual rules: responses are slow and variable, costs scale with input size, outputs are non-deterministic and models change underneath you. This guide covers the API patterns that handle those properties well, with examples drawn from how major model providers design their own APIs.

TopicsArchitecture and ModernizationGenerative AI and LLMsMobile App Development

Key takeaways

  • Never let web or mobile clients call a model provider directly. Put your own API in between to hold secrets, enforce permissions, budget tokens and log usage.
  • Choose the interaction style by response time: synchronous for short answers, streaming for interactive text, and asynchronous jobs with status or webhooks for anything that can take more than about 30 seconds.
  • Rate-limit by tokens and cost, not only by requests, and give clients clear limit headers and retry guidance.
  • Version the contract of your feature, not the model. Pin model versions behind your API and change them only after evaluation.
  • Treat prompts, retrieved content and model output as untrusted: validate inputs, guard against prompt injection, and filter and validate outputs before they reach users or other systems.

Most teams add their first AI feature by calling a model provider from the backend and returning the result. That works for a prototype. In production, the properties of language models start to shape the API around them: a single request can take a fraction of a second or two minutes, cost depends on how much text goes in and out, the same input can produce different outputs, and the model you depend on will be updated or retired.

This guide is about the API you build between your applications and the AI features behind them — the endpoints your web app, mobile app or partners call. It draws on patterns that model providers use in their own APIs, because they solved the same problems at much larger scale. For the overall architecture of AI applications, see our guide to choosing AI application architecture.

Why you need your own AI API layer

Calling a provider directly from a browser or mobile app exposes your API key, gives up control of cost and makes it impossible to enforce business rules. A dedicated layer — sometimes called an AI gateway — gives you one place to:

  • hold secrets and rotate provider keys without app releases;
  • authenticate and authorise users, and apply tenant or plan entitlements;
  • assemble context — retrieve documents, add instructions, trim history — on the server, where it cannot be tampered with;
  • budget tokens and cost per user, tenant and feature;
  • route between models or providers and fail over when one is unavailable;
  • validate outputs before returning them;
  • log and measure usage, latency, cost and quality.

A clean pattern is to expose feature-level endpoints — summarise a ticket, draft a reply, extract invoice fields — rather than a generic “send this prompt” endpoint. Feature endpoints keep prompts on the server, make permissions and limits specific, and let you change models or prompts without touching clients.

Choose the interaction style by response time

StyleUse whenHow it worksClient experience
————
Synchronous request–responseShort outputs, typically under a few seconds: classification, extraction of a few fieldsClient waits for the full responseSimple; show a spinner
StreamingInteractive text such as chat, drafting or explanationsServer sends tokens as they are generated, usually over server-sent eventsText appears progressively; perceived latency drops sharply
Asynchronous jobLong tasks: document processing, multi-step agents, batch analysisClient creates a job, receives an ID, then polls a status endpoint or receives a webhookProgress indicator; user can leave and return
BatchLarge volumes that are not time-sensitiveSubmit many items; collect results laterNightly or background processing; often cheaper

Many features combine styles: stream a draft to the user, then run a slower quality check as a background job.

Streaming done properly

Server-sent events (SSE) are the most common transport for streaming model output. They run over ordinary HTTP, work through most proxies and suit one-way token streams. Anthropic’s Messages API is a useful reference design: a stream begins with a message_start event, then each content block is sent as a start event, a series of delta events and a stop event, followed by message_delta events carrying cumulative usage and a final message_stop. Ping events keep the connection alive, and errors such as an overloaded condition can arrive as an error event in the middle of the stream.

Lessons to copy into your own API:

  • Use typed events. Separate events for text deltas, tool or progress updates, usage and completion make clients simpler and let you add event types later. Tell clients to ignore unknown types.
  • Send keep-alives. Proxies and load balancers often close idle connections; periodic ping events prevent that during long pauses.
  • Report errors in-band. Once streaming has started, the HTTP status is already 200. Send a structured error event and let the client decide whether to retry or show partial output.
  • Send usage at the end. Final token counts let clients and your billing system record the true cost.
  • Support cancellation. When a user closes the view or presses stop, cancel the upstream model call so you stop paying for tokens nobody will read.
  • Plan for interruption. Store partial output server-side with a response ID, so a reconnecting client can fetch what was generated rather than starting again.
event: response.starteddata: {"response_id": "rsp_7Hc2", "feature": "draft_reply", "model_version": "2026-10"} event: text.deltadata: {"text": "Thanks for letting us know about the delay. "} event: text.deltadata: {"text": "Your order left our warehouse this morning..."} event: response.completeddata: {"input_tokens": 1840, "output_tokens": 212, "finish_reason": "stop"}

Long-running work as jobs

Anything that can exceed roughly 30 seconds — parsing a 200-page contract, running an agent, processing a batch — should be a job, not a held-open request. Mobile networks drop, users background apps and gateways time out.

  1. POST /v1/document-reviews creates the job and returns 202 Accepted with a job ID and a status URL.
  2. GET /v1/document-reviews/{id} returns status (queued, running, needs_input, succeeded, failed, cancelled), progress and, when finished, the result or a link to it.
  3. Webhooks notify servers of completion; mobile apps can use push notifications. Our guide to event-driven APIs covers signing and retries.
  4. POST /v1/document-reviews/{id}/cancel stops work and spending.

Accept an Idempotency-Key header on job creation so a client retrying after a network failure does not start, and pay for, the same job twice.

Manage context and input size

Model cost and latency grow with input size, and every model has a context limit. Design for it explicitly:

  • Validate size at the edge. Reject or truncate inputs above a documented limit with a clear error (413 or 422 with a machine-readable code), rather than failing deep inside the pipeline.
  • Count tokens, not characters. Use the provider’s tokenizer or token-counting endpoint for budgets; character estimates vary by language.
  • Retrieve rather than send everything. For large documents, chunk and retrieve relevant passages instead of passing whole files.
  • Summarise long histories. Keep recent turns verbatim and replace older turns with a summary.
  • Expose limits in documentation and responses so client teams can design around them.

Our guide to reducing LLM token costs covers these techniques and their quality trade-offs in more depth.

Rate limits and quotas that reflect cost

A request that sends 50 tokens and one that sends 50,000 cost very different amounts. Providers therefore limit not just requests per minute but input and output tokens per minute. Anthropic, for example, returns headers on every response showing the limit, remaining allowance and reset time for requests, input tokens and output tokens, and a retry-after header with a 429 response.

Apply the same thinking to your own API:

LimitScopePurpose
———
Requests per minuteUser, API keyProtect against floods and scripts
Tokens per minuteUser, tenantProtect provider limits and latency for everyone
Monthly cost or token quotaTenant, planEnforce commercial plans and budgets
Concurrent jobsTenantPrevent one customer filling the job queue
Maximum output lengthFeatureKeep responses and costs predictable

Return remaining allowance in response headers and a Retry-After value with 429 responses.

Queue requests when you are close to provider limits rather than failing immediately, and prioritise interactive traffic over background jobs.

Errors and retries

SituationYour API shouldClient should
———
Invalid or oversized inputReturn 400, 413 or 422 with a specific error codeFix the request; do not retry unchanged
User over quotaReturn 429 with Retry-After and quota detailsWait or prompt the user to upgrade
Provider rate-limited or overloadedRetry with exponential backoff and jitter, fail over if configured, then return 503 with Retry-AfterRetry later; show a friendly message
Model output fails validationRetry once with a repair instruction, then return a controlled fallbackShow fallback or route to a human
Content blocked by safety filterReturn a specific, non-revealing error codeExplain politely; do not retry automatically
Timeout on a synchronous callConvert the feature to a job, or return 504 with guidanceUse the job endpoint for large inputs

Distinguish errors the client can fix from errors only time or your team can fix.

Version the feature, pin the model

Model providers release new versions and retire old ones on their own schedule. Your clients should never notice unless you decide they should.

  • Version your API contract (for example /v1/) based on request and response shapes, not on which model runs behind it.
  • Pin specific model versions in configuration, not floating aliases that change silently.
  • Upgrade models through evaluation. Run the new model against your evaluation set for each feature, compare quality, latency and cost, then roll out gradually behind a flag.
  • Return a model or prompt version identifier in responses and logs so you can trace a complaint to the exact configuration that produced it.
  • Plan for deprecation dates. Track provider retirement notices and schedule evaluations well before deadlines.

Structured outputs

When the result feeds other software — extracted fields, classifications, actions — ask the model for JSON that conforms to a schema, using the provider’s structured-output or tool-calling features where available. Then validate the result on your server anyway. Reject or repair invalid output, enforce business rules (an extracted invoice total must equal the sum of lines) and never pass unvalidated model output to a database, shell or HTML page.

Security and privacy

The OWASP Top 10 for LLM Applications highlights the risks most relevant to an AI API layer:

  • Prompt injection (LLM01). User input and retrieved documents can contain instructions. Keep system instructions on the server, separate untrusted content clearly, and limit what the model’s output can trigger.
  • Sensitive information disclosure (LLM02). Enforce permissions before retrieval, redact personal data where possible and avoid sending secrets to models.
  • Improper output handling (LLM05). Escape and validate outputs before rendering or executing them.
  • System prompt leakage (LLM07). Assume prompts can be extracted; never put credentials or sensitive logic in them.
  • Unbounded consumption (LLM10). Enforce token, cost and concurrency limits.

Add the usual API controls too: strong authentication, per-tenant isolation, encryption in transit, data-retention rules for prompts and outputs, and contractual checks on how providers use your data.

Authentication and multi-tenancy

AI features often process the most sensitive data in a product — documents, conversations, customer records — so the access model needs particular care:

  • Authenticate the end user, not just the app. Pass the user’s identity to the AI layer so retrieval and tools act with that user’s permissions.
  • Isolate tenants everywhere: in retrieval indexes, caches, conversation history, logs and fine-tuning data. A cache key that omits the tenant is a data leak waiting to happen.
  • Separate service credentials per feature so a compromised or misbehaving feature cannot reach data used by another.
  • Keep provider keys server-side, rotate them regularly and set spending limits at the provider as a backstop.

Testing an AI API

Conventional API tests still apply — contracts, authentication, error codes, load — but AI features need more:

Test typeWhat it checksWhen to run
———
Contract testsRequest and response schemas, event names in streams, error codesEvery build
Golden-set evaluationOutput quality on a fixed set of inputs with expected results or grading rubricsEvery prompt, model or retrieval change
Structured-output validationSchema conformance and business-rule checks across many samplesEvery build and nightly
Adversarial testsPrompt injection, attempts to extract system prompts, requests outside scopeEvery release
Load and soak testsLatency to first token, throughput, behaviour near provider limitsBefore launch and before major traffic changes
Failover testsBehaviour when the provider is slow, rate-limited or unavailableRegularly, in staging

Use a stubbed model for fast deterministic tests and the real model for evaluation runs.

Observability

Log, for every call: feature, user and tenant identifiers, model and prompt version, input and output tokens, latency to first token and to completion, cost, cache use, finish reason, validation result and any user feedback. Redact personal data before storage. Dashboards by feature and tenant answer the questions that will come up first: what is this costing, who is using it, is it getting slower and is it still good?

A checklist before launch

  • Feature-level endpoints with server-side prompts and context assembly.
  • Streaming with typed events, keep-alives, cancellation and in-band errors.
  • Jobs with idempotency keys for long-running work.
  • Documented input limits and token-based quotas with clear headers.
  • Pinned model versions and an evaluation gate for changes.
  • Schema validation of structured outputs.
  • Prompt-injection, permission and data-retention controls.
  • Logging of tokens, cost, latency and versions per call.

Frequently asked questions

Should mobile apps call the model provider directly to reduce latency?

No. It exposes credentials and removes your ability to enforce limits and rules. The extra hop through your API is small compared with model generation time, especially with streaming.

SSE or WebSockets for streaming AI responses?

SSE is usually enough: model output flows one way and SSE works over ordinary HTTP. Choose WebSockets when you need frequent two-way messages on the same connection, such as real-time voice or collaborative editing.

Can we cache AI responses?

Yes, for deterministic or repeated requests such as classifying identical inputs or answering common questions from fixed content. Include the model and prompt version in the cache key, set expiry times, and never share cached answers across users when content depends on their permissions.

How do we handle a provider outage?

Retry with backoff, then fail over to a second model or provider for features where you have evaluated one, or degrade gracefully with a clear message. Test the failover path regularly.

Sources and methodology

Facts in this article were checked against the sources below on 6 November 2026. Directory data (ratings, review counts, rate bands and team sizes) changes over time and is shown as published on the date accessed. Illustrative examples are labelled as such and are not quotes.

  1. Anthropic documentation: Streaming messages — accessed 6 November 2026. Event sequence (message_start, content blocks, message_delta, message_stop), ping events, in-stream error events, recovering interrupted streams
  2. AWS documentation: Rate limits for Claude Platform on AWS — accessed 6 November 2026. RPM, input and output tokens per minute; anthropic-ratelimit-* headers; retry-after on 429
  3. OWASP: Top 10 for LLM Applications 2025 — accessed 6 November 2026. LLM01, LLM02, LLM05, LLM07 and LLM10

Adding AI features to your web or mobile apps?

Share your current API and the AI features you are planning. We will help you design endpoints, streaming, limits and safeguards that keep the experience fast, affordable and secure.