← Blog

Claude API Multi-Turn Conversation History Guide

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

The Claude API is stateless — it does not remember anything between requests. To build a multi-turn conversation, you have to send the entire conversation history back to the API on every single call, structured as an array of message objects with alternating user and assistant roles. There is no session ID, no "continue this chat" flag, no server-side memory. Whatever context Claude has access to is exactly what you put in the messages array of that request.

This is different from how a chat UI feels to end users, where the conversation "just continues." Under the hood, every one of those turns is a fresh API call carrying the full transcript so far. Understanding this is the key to building anything conversational on top of Claude — whether that's a support bot, a coding assistant, or an internal tool.

How conversation history actually works

A basic multi-turn request looks like this:

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-3-5-sonnet-20241022",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "What is a monorepo?"},
      {"role": "assistant", "content": "A monorepo is a single repository that holds code for multiple projects..."},
      {"role": "user", "content": "What are the downsides?"}
    ]
  }'

Notice that the second user message ("What are the downsides?") only makes sense because the previous exchange is included above it. Claude has no idea what "the downsides" refers to unless you send the prior turns along with it.

Rules that matter here:

Building the message array on your side

In practice, most apps keep a conversation as a list in a database (or in memory for short-lived sessions) and append to it after each exchange:

let history = [];

function addTurn(role, content) {
  history.push({ role, content });
}

addTurn("user", "Summarize this contract clause for me.");
// send `history` to Claude, get a reply
addTurn("assistant", replyText);

addTurn("user", "Now rewrite it in plain English.");
// send the *whole* updated `history` array again

Each request carries the growing array. This is simple for short conversations, but it has a real cost implication: you pay input token costs for the entire history on every single turn, not just the new message. A 20-turn conversation means turn 20 re-sends and re-bills the tokens for turns 1 through 19 as input.

Managing history as conversations grow

Once conversations get long, sending the full transcript every time becomes expensive and can eventually bump into the model's context window. A few practical strategies:

None of this requires special API features — it's application logic you write around the plain messages array. The API itself is intentionally simple: give it messages, get a reply.

Where this gets harder in production

If you're shipping a real product on top of Claude, a few things compound quickly:

This is the layer SubToAPI adds on top of your existing Claude access: it turns your subscription into a proper HTTPS API with per-application keys (sub_live_...), streaming support, and usage metadata per request, so you can build multi-turn features without also building key management and billing plumbing from scratch. The conversation history logic above — appending messages, deciding when to prune or summarize — works exactly the same way against SubToAPI's endpoint as it does against a direct Claude integration. See the quickstart and the messages endpoint docs for the exact request shape, or streaming if you're rendering replies token by token in a chat UI.

If you're evaluating plans for a small team building conversational features, the pricing page breaks down Solo, Team, and Scale tiers, and you can start with a free trial at signup.

questions

Does the Claude API remember previous messages automatically? No. The API is stateless — every request must include the full conversation history in the messages array. Nothing is stored or remembered between calls unless you send it yourself.

How do I keep conversation history without exceeding the context window? Truncate older turns, summarize past exchanges into a single compressed message, or move durable facts into the system prompt so the rolling messages array stays short and recent.

Do I get billed for the entire conversation history on every turn? Yes. Every message you include in the messages array counts as input tokens on that request, even if Claude already "saw" it in a previous call. Longer histories mean higher per-turn cost as the conversation grows.

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 →