← Blog

Claude API Chat History Pagination: How It Actually Works

2026-10-14 · 5 min read · SubToAPI Team

If you're searching for "Claude API chat history pagination," you've probably hit the same wall most developers do: there's no GET /v1/conversations?page=2 endpoint. Claude's Messages API is stateless — it doesn't store your chat history server-side, and it doesn't expose a paginated list of past turns. Every request you send must include the full conversation as a messages array, and Anthropic's servers forget it the moment the response is returned.

So the pagination you're actually looking for isn't something the Claude API provides — it's something you build, on top of however you're storing conversation history (a database, Redis, a file, whatever). This article covers how that typically works: storing turns with cursors, paginating them for a UI, and keeping your outgoing messages array within context limits so you're not re-sending (and re-paying for) your entire chat history on every call.

Why Claude doesn't paginate chat history for you

The Messages API is designed around a simple contract: you send a list of messages, you get one back. There's no session ID, no server-side thread object, no /history endpoint. This is different from some chat-oriented APIs that maintain threads server-side with their own pagination semantics.

The upside is flexibility — you fully control what context Claude sees, how long you keep it, and whether you summarize, redact, or truncate it. The downside is that building a "chat history" feature (the kind users expect in a product with a sidebar of past conversations) is entirely on your application layer.

Where pagination actually belongs

Pagination shows up in two separate places once you build a real chat product:

  1. Paginating stored conversations/messages in your own database — for a UI that shows "load more" or infinite scroll on past chats.
  2. Managing the size of the messages array you send to Claude — trimming or summarizing older turns so you stay under context limits and avoid paying for tokens you don't need.

These are different problems with different solutions. Let's go through both.

1. Paginating stored messages for your UI

If you're persisting messages in Postgres, Mongo, or similar, cursor-based pagination is the right pattern — it's stable even as new messages are inserted, unlike offset-based pagination.

SELECT id, role, content, created_at
FROM messages
WHERE conversation_id = $1
  AND created_at < $2   -- cursor: created_at of the last message you already loaded
ORDER BY created_at DESC
LIMIT 20;

On the client side, you fetch the next page by passing the created_at (or an auto-increment id) of the oldest message you've already rendered:

async function fetchHistory(conversationId, cursor) {
  const url = new URL(`/api/conversations/${conversationId}/messages`, location.origin);
  if (cursor) url.searchParams.set("before", cursor);
  url.searchParams.set("limit", "20");
  const res = await fetch(url);
  return res.json(); // { messages: [...], nextCursor: "..." }
}

This is the layer most people mean when they say "chat history pagination" — it's about your own storage, not Claude's API.

2. Trimming history before you send it to Claude

Separately, you need to decide how much of that history actually gets sent in the messages array on each request, since Claude's context window is finite and larger payloads cost more tokens.

A common pattern: keep the last N turns verbatim, and summarize everything older into a single system or assistant message.

function buildMessages(fullHistory, maxTurns = 10, summary = null) {
  const recent = fullHistory.slice(-maxTurns);
  const messages = [];
  if (summary) {
    messages.push({ role: "user", content: `Conversation summary so far: ${summary}` });
  }
  return [...messages, ...recent];
}

You regenerate the summary periodically (every 20–30 turns, say) with a cheap, short call to Claude itself, then drop the raw older turns from what you send — though you keep them in your database for pagination/display purposes.

Putting it together with SubToAPI

If you're calling Claude through SubToAPI, the request shape is identical to the standard Messages API — you're just authenticating with a sub_live_... application key instead of managing Anthropic credentials directly:

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 our conversation so far in 2 sentences." },
      { "role": "assistant", "content": "..." },
      { "role": "user", "content": "Now continue where we left off." }
    ]
  }'

The statelessness is the same — SubToAPI doesn't store or paginate your chat history either, since it's a passthrough layer for Claude requests with API keys, streaming, usage metadata, and team seats on top. What it does give you is visibility into token usage per key, which is genuinely useful when you're deciding how aggressively to trim history: you can see in the dashboard exactly how much a bloated messages array is costing you per request, per app key, or per team member.

See the quickstart for setup and the messages docs for the full request/response shape. If you're streaming long conversations back to a UI, the streaming docs cover how partial responses arrive so you can render them incrementally while you append to your own paginated history store.

A practical checklist

questions

Does the Claude API have a built-in chat history or sessions endpoint? No. The Messages API is stateless — you send the full conversation each time, and there's no server-side thread storage or pagination endpoint to query past turns.

How should I paginate chat history in my own app? Use cursor-based pagination against your own database (ordering by timestamp or ID), not offset-based pagination, since offsets break when new messages are inserted concurrently.

Will sending my entire chat history every request get expensive? Yes, since Claude bills by tokens in the full request. Trim older turns, summarize them periodically, and only resend the recent window plus a summary to control both context length and cost.

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 →