LearnThatStack Ace your next interview

LLM APIs & Integration

Anthropic, OpenAI and Gemini APIs as of September 2026 Checked Sep 2026 69 code snippets

The model

  • An LLM API is stateless. Every call carries the system prompt, the whole conversation and the tools. You append the model's reply before the next call.
  • You pay per token, at separate prices for input and output. Output costs several times more, and hidden reasoning tokens bill as output.
  • Read the stop reason before the text. A reply cut off by max_tokens and a tool call both come back as HTTP 200, with no error.
  • The model never runs your code. It asks for a tool call, and your server runs it and sends back the result. The loop repeats until the model stops asking.
  • Prompt caching matches an exact prefix. Keep the tools and system prompt fixed at the front, and put whatever changes at the end.
Browseryour frontendYour serverholds the API keyProvider APIthe modelSENDuser messagewhole history + system, toolsLOOPtool_use name + inputtool_result you ran the toolREPLYend_turn text + usagestreamed text
The model keeps no memory, so your server resends the whole history every call. It runs each tool the model asks for and loops until a reply ends in end_turn.

Requests & auth

the call every feature starts with

Pick a provider API

Call each provider's APIPOST /v1/messagesPOST /v1/responsesPOST /v1beta/models/{model}:generateContentAnthropic, OpenAI, then Gemini. Clouds like Bedrock resell the same models.
Choose the official SDK or raw HTTPThe SDK. It handles auth, retries, timeouts and streams.
Send a turn with OpenAI's Responses APIclient.responses.create(model=m, input=q)Send input, get a typed output list.
Continue a chat without resending itprevious_response_id=r1.idOpenAI keeps the history.
Replace the Assistants APIUse Responses. OpenAI removed it on August 26, 2026.

TipChat Completions still works. Keep it for code that also targets other providers.

Build a chat request

{"model": "claude-sonnet-4-6", "max_tokens": 1024,required "system": "You are a concise Python tutor.", "messages": [ {"role": "user", "content": "What is a decorator?"}, {"role": "assistant", "content": "It wraps a..."},sent again {"role": "user", "content": "Show me one."}]}
Give the model memory of earlier turnsResend the whole chat, with each reply appended.
Set the system prompt on OpenAI or Gemini"role": "developer""systemInstruction"OpenAI, then Gemini.
Find the reply in the responsecontent on Anthropic, choices on OpenAI, candidates on Gemini.

TrapAnthropic puts text and tool calls in one block list. OpenAI splits them into content and tool_calls.

Authenticate and keep the key safe

Send the API keyx-api-keyAuthorization: Bearerx-goog-api-keyAnthropic, OpenAI, then Gemini.
Add Anthropic's version headeranthropic-version: 2023-06-01Every request fails without it.
Add LLM features to a frontendCall your own server. It checks the user and holds the key.

TrapNext.js inlines NEXT_PUBLIC_ variables into the bundle. Anyone can read a key sent to the browser and spend your money.

Tokens & cost

what you pay for, and how to count it

Tokens and the context window

Know what you pay forInput and output tokens. Output costs several times more.
Guess a token count from textOne token is about 4 English characters. Code and JSON take more.
Know what fills the context windowPrompt, history, tools and the output, in one budget.
Send more input than the window holdsIt fails with a 400 before generating. Quality drops well before that.

TrapOn many models max_tokens counts against the window. A large value can reject a prompt that fits.

Count tokens and read usage

Count a Claude requestclient.messages.count_tokens(**req)Free, on the server. Close to the bill.
Count an OpenAI or Gemini requesttiktoken.encoding_for_model(m)client.models.count_tokens(**req)tiktoken is local and close. Gemini's is exact.
Price an Anthropic callcache_read_input_tokenscache_creation_input_tokensOutside input_tokens. Add each at its own rate.
Price an OpenAI callprompt_tokens_details.cached_tokensInside prompt_tokens. Subtract, then price the rest.
Get usage from an OpenAI streamstream_options={"include_usage": True}It comes on the final event.

TrapCounts don't carry across models. tiktoken is wrong for Claude, and Claude 4.7+ counts about 30% more than older Claude.

Output, sampling & reasoning

cap, steer and check what the model writes

Cap output and check why it stopped

Cap how much the model writes"max_tokens": 1024max_completion_tokens=1024"maxOutputTokens": 1024Anthropic, OpenAI, then Gemini. Only Anthropic requires it.
Spot a reply the cap cut offstop_reason: "max_tokens"finish_reason: "length"finishReason: "MAX_TOKENS"Anthropic, OpenAI, then Gemini.

TrapHitting the cap raises no error. You still pay for the tokens, and cut-off JSON won't parse.

Sampling and reasoning effort

Make output more or less random"temperature": 0.2"top_p": 0.9Temperature scales the odds. top_p keeps the likeliest tokens. Tune one.
Set temperature on a reasoning modelClaude 4.7+ returns a 400. GPT-6 allows it only at effort none.
Set reasoning effort on Claude"thinking": {"type": "adaptive"}"output_config": {"effort": "high"}Pass thinking blocks back unchanged in a tool loop.
Set reasoning effort on OpenAI or Geminireasoning_effort="high"thinking_level="high"OpenAI, then Gemini 3. It replaces thinking_budget.

TipLeave room in max_tokens. Thinking bills as output and shares the cap.

Traptemperature: 0 doesn't make output repeatable. Batching and floating-point effects still vary it.

Streaming

show text while the model writes it

Turn on streaming

No streammodel writesall textStreammodel writesfirst wordstime

Both replies take the same time to write. Each dot is text reaching the screen. Streamed text starts almost at once, so the user reads as the model writes.

Stream a reply"stream": true
Say why chat apps streamFirst words in under a second. It also avoids proxy timeouts.

TrapUsage arrives at the end, and you can't validate the full text before the user sees it.

Read the event stream

event: message_startinput tokensevent: content_block_startone per blockevent: content_block_deltarepeatsevent: content_block_stopevent: message_deltastop_reason, usageevent: message_stop
Parse one server-sent eventAn event: line, a data: line of JSON, then a blank line.
Rebuild tool arguments from a streaminput_json_deltaJoin the pieces. Parse when the block stops.

TrapA ping or an error event can arrive at any point. An error cuts the stream short.

Handle the stream in the client

Keep characters whole across chunksdecoder.decode(chunk, { stream: true })
Update the UI without stalling the tabrequestAnimationFrame(paint)One paint per frame, not per chunk.
Stop a reply mid-streamcontroller.abort()Call it from a stop button or an idle watchdog.
Prove a stream finishedmessage_stopdata: [DONE]Anthropic, then OpenAI. Nothing else proves it.
Recover a long answer that broke offSend the partial text back as an assistant turn. Ask for the rest.

TipA chunk is any slice of bytes. Keep one buffer per block, and skip event types you don't know.

TrapA failure mid-stream comes after status 200. Drop half-built tool JSON, never run it.

Tools & MCP

let the model ask your code to act

Declare and control tools

Describe a toolA name, a JSON Schema, and a description of when to use it.
Spot a tool callstop_reason: "tool_use"finish_reason: "tool_calls"Anthropic, then OpenAI, whose arguments are a JSON string.
Guarantee arguments match the schema"strict": trueOtherwise validate the arguments yourself.
Force the model to call a tool{"type": "any"}"required"Anthropic, then OpenAI. Claude Opus 5.5 rejects it with a 400.
Make calls run one at a time"disable_parallel_tool_use": trueparallel_tool_calls=FalseAnthropic, then OpenAI.

TipChanging the tools or tool_choice mid-chat breaks the prompt cache.

TrapForce a tool on the first turn only. Left on, the model can never answer, so it loops.

Run the tool loop

Send the tool results backAppend the assistant turn as is, then a tool_result per tool_use_id.
Know when the loop endsWhen a turn has no tool call. On max_tokens, don't run the cut-off call.
Stop a runaway loopCap the iterations, the spend and the wall-clock time.
Return several calls from one turnAll in one user message on Anthropic. One tool message per call on OpenAI.

TrapEvery call needs a matching result, failures included. A missing one is an error, not a warning.

MCP and untrusted tool results

Say what MCP isAn open protocol on JSON-RPC that connects apps to tools and data.
Use an MCP server's tools with a provider APIList its tools, convert them to the provider's schema, forward each call.
Handle text a tool fetched from the webTreat it as data. From then on, allow only read-only tools.
Let the model trigger a real actionCheck it in code against an allowlist. Confirm anything you can't undo.

TipFunction calling is how the model asks for a tool. MCP is how your app finds and runs it.

TrapWrapping fetched text in a labelled block is a hint to the model, not a fence.

JSON & schemas

get output your code can parse

JSON mode and structured outputs

Get valid JSON from OpenAI{"type": "json_object"}Your messages must mention JSON.
Enforce a schema on OpenAI{"type": "json_schema"}"strict": true
Enforce a schema on Anthropicoutput_config.formatOr a strict tool. Claude 4.6+ rejects a prefilled {.
Get JSON from GeminiresponseMimeTyperesponseSchemaThe first gives JSON. The second adds a schema.

TipStructured outputs mask every token that would break the schema. Asking in the prompt can't promise that.

TrapJSON mode fixes the syntax only. Check key names, types and required fields yourself.

Where schemas still fail

Write a schema the provider accepts"additionalProperties": falseOnly a subset works. Anthropic's SDKs strip minimum and maxLength.
Handle an object cut off halfwayCheck the stop reason first, and raise the budget. Don't retry the parse.
Handle a refusalIt returns prose. Use a fallback path, not a repair loop.
Catch valid JSON with wrong valuesCheck business rules in code. Feed the error back once, then dead-letter it.

Images, PDFs & audio

send more than text

Send images and PDFs

Put an image in a message"type": "image""type": "input_image"inline_dataAnthropic, OpenAI, then Gemini.
Keep image costs downResize first. Claude shrinks past a 1568px edge, or 2576px on 4.7+.
Put a PDF in a message"type": "document""type": "input_file""mime_type": "application/pdf"Anthropic, OpenAI, then Gemini. Each reads pages as images and text.
Know the PDF limitsClaude takes 32 MB and up to 600 pages. OpenAI takes 50 MB and 100, Gemini 50 MB and 1,000.

TrapBase64 grows the payload by about a third. Upload big or repeated files once through a Files API.

Take voice input

Build voice input that works with any modelTranscribe first, then send plain text. Claude takes no audio.
Transcribe on OpenAIPOST /v1/audio/transcriptionsgpt-transcribe, which replaces whisper-1.
Send audio straight to the modelGemini takes it, at 32 tokens a second. Use it when tone matters.

TipFor two-way voice, use OpenAI's Realtime API or Gemini's Live API.

Caching & batch

pay less for repeated and offline work

Cache a prompt prefix

Cache everything up to a block on Anthropic"cache_control": {"type": "ephemeral"}Up to four breakpoints, or one at the top level.
Price a cache write and a readA write costs 1.25x input, or 2x for the 1-hour TTL. A read costs 0.1x or less.
Know when caching pays offBy the second call within 5 minutes, or the third on the 1-hour TTL.
Cache on OpenAIprompt_cache_key="support-bot"Automatic, with no storage fee.
Cache on GeminiAutomatic on 2.5+. Explicit caches bill hourly storage.

TrapOne changed byte early in the prefix misses everything after it. The order is tools, then system, then messages.

Keep long chats cached

Trim a long chat without losing the cacheCompact old turns into a frozen summary up front. Append new turns.
Cache the growing conversationMove the breakpoint to the newest message each turn.
Share one cache across tenantsShared prompt first, then tenant data, then turns. An org per tenant splits it.

TrapA sliding window that drops the oldest turn changes the prefix, so every request misses.

Run a batch job

Pick work for a batchEvals, bulk labels, backfills. Half price, results within 24 hours.
Match results to requests"custom_id": "row-1"Results come back in any order.

TrapA batch can succeed while some requests in it fail. Check every result's status.

Errors, retries & limits

survive 429s, timeouts and outages

Handle a 429 and plan capacity

Wait out a rate limitretry-afterWait that long. With no header, back off with jitter.
Spot a 429 that never clearscredit_balance_exhaustedenforced_spend_limit_reachedOpenAI, then Anthropic. Fail fast.
Name the rate limitsRequests and tokens per minute, daily caps and concurrency.
Budget tokens per minute on OpenAIPeak requests times input plus max_tokens. OpenAI counts it up front.

Retries and timeouts

Pick the errors to retryTimeouts, network errors, 429s and 5xx. Never a 400, 401, 403 or 404.
Space out retriesrandom.uniform(0, min(cap, base * 2 ** n))Full jitter. Stop after about three tries.
Run your own retry loopAnthropic(max_retries=0)SDKs already retry twice. Don't stack layers.
Tighten the SDK defaultsAnthropic(timeout=30.0, max_retries=1)Defaults are 10 minutes and 2 retries, so up to 30 minutes.
Beat the platform's own timeoutProxies and serverless cut at 30 or 60 seconds. Set yours lower.
Put a time limit on a long streamThe read timeout counts gaps between chunks. Add an overall deadline.

TrapA client timeout doesn't stop the model. You can pay for tokens you never read.

Layer retries, breakers and fallbacks

deadline: the whole user request, like 30s fallback: primary, other provider, cached breaker per provider, model, region hedge: a copy at p95, first reply wins retry: jittered, from a shared budget timeout per attempt, inside the rest
Make a tool call safe to retryKey it on session, turn, tool and arguments. Claim the key before acting.
Decide what trips the circuit breakerTimeouts, 5xx and resets. A 429 waits once and doesn't count.

TrapA resampled response gets a fresh tool_use_id, so never key side effects on it.

Routing & production

run LLM calls across providers and at scale

Route and fall back across providers

Route requests to modelsBy task class, each with an ordered list of pinned model IDs.
Pick what triggers a fallback429s, 5xx, timeouts and bad schemas. Never a 400, which fails everywhere.
Keep a conversation on one modelRoute by conversation ID. A switch drops the cached prefix.

TipOne wrapper for every provider shrinks to their shared features. The rest leaks back as if branches.

TrapA fallback starts with a cold cache and another tool-call shape. Test its prompt and parser in CI.

LiteLLM or OpenRouter

Run your own gatewayThe LiteLLM proxy, with virtual keys and budgets per team.
Reach hundreds of models with one key and one billOpenRouter, a hosted OpenAI-compatible gateway. It charges a fee on credits.
Go direct instead of through a gatewayFor zero data retention, a BAA, spend discounts or new features first.

TrapA gateway sits in your hot path. Run two replicas or more, and keep its timeouts inside yours.

Log and deploy in production

Log an LLM callOne record per HTTP attempt, with request ID, served model, stop reason and usage.
Watch the fleet's healthTime to first token, latency, errors by status, cache hits and cost.
Set SLOs for an LLM productTime to first token, inter-token latency and cost per completed task.
Log usage from a serverless functionwaitUntil(logUsage(resp))Or await it. The instance freezes once you respond.
Run an agent loop that takes minutesRun it as a durable job. Return a run ID, and checkpoint each step.

TrapA truncated reply returns HTTP 200. Alert on stop_reason, or it looks healthy in every error metric.

Found this useful? Pass it on.
Pro · $10/mo

This sheet stays free. With Pro, you can:

  • Every answer on this sheet. Read the full answer to all 52 questions it links, not just the 7 free ones.
  • My sheet. The cards you star and the ones you miss in Quiz me, from every sheet, on one page to quiz and print.
  • PDFs. Download this sheet and My sheet, laid out for A4, with every question a link to its answer.
  • The rest of Pro. Every answer in the question library, and 1,000 AI credits a month.