Claude API Text Summarization Tutorial (With Code)
Summarizing text with Claude's API comes down to three things: sending the right prompt, choosing sane parameters (max tokens, temperature), and handling documents that are too long for a single request. This tutorial walks through all three with working code, so you can go from "paste text in, get a summary out" to a production-ready endpoint.
If you just want the short version: send your text as a user message with clear instructions about length and format, set temperature low (0–0.3) for consistency, and cap max_tokens to control summary length. For anything longer than a few thousand words, you'll need to chunk and summarize in passes. The rest of this article covers each step in detail.
Setting Up the Basic Summarization Call
Claude's Messages API takes a model, a max_tokens limit, and a messages array. For summarization, the simplest approach is a single user message containing the text plus an instruction:
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-sonnet-4-5",
"max_tokens": 300,
"temperature": 0.2,
"messages": [
{
"role": "user",
"content": "Summarize the following article in 3 bullet points, focusing on concrete takeaways:\n\n<article text here>"
}
]
}'
A few parameter choices matter more than people expect:
temperature: Low values (0–0.3) keep summaries consistent and reduce the chance of the model adding details not in the source. Higher temperatures are fine for creative rewrites but not for factual condensation.max_tokens: This is a hard cap, not a target. If you ask for "a 2-sentence summary" but setmax_tokens: 1000, Claude will usually respect the instruction, but setting a tighter cap (e.g., 150–300) gives you a safety net against runaway output.- System prompt vs. inline instruction: For one-off calls, an inline instruction is fine. If you're summarizing at scale with consistent formatting requirements, move the instruction to a
systemparameter so your user content stays purely the text being summarized.
Writing a Prompt That Produces Useful Summaries
Vague prompts produce vague summaries. "Summarize this" gives you a generic paragraph; a more specific prompt gives you something actually usable downstream. Compare:
Weak: Summarize this.
Better:
Summarize the following support ticket in exactly 2 sentences.
Sentence 1: the customer's core problem.
Sentence 2: the resolution or current status.
Do not include greetings or sign-offs from the original text.
<ticket text>
The pattern that works well: state the output format first (bullet count, sentence count, or word limit), state what to include and exclude, then paste the source text last. Putting instructions before the content means Claude doesn't have to "look back" to figure out what you want.
For structured summaries (e.g., extracting specific fields), ask for JSON output directly:
Extract a summary from the text below as JSON with keys "headline", "key_points" (array of 3 strings), and "sentiment" (positive/neutral/negative). Return only valid JSON, no markdown formatting.
<text>
This is useful when the summary feeds into another system rather than being read directly by a human.
Summarizing Long Documents
Claude's context window handles long inputs well, but two problems still show up in practice: cost (you're paying for every token, including the full document on every call) and quality drop-off on very long single-pass summaries. The standard fix is map-reduce summarization:
- Split the document into chunks (by paragraph, section, or a fixed token count).
- Summarize each chunk independently.
- Concatenate the chunk summaries and run a final summarization pass over them.
async function summarizeChunk(text) {
const res = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"x-api-key": process.env.ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify({
model: "claude-sonnet-4-5",
max_tokens: 200,
messages: [
{ role: "user", content: `Summarize in 3 sentences:\n\n${text}` },
],
}),
});
const data = await res.json();
return data.content[0].text;
}
async function summarizeLongDocument(chunks) {
const partials = await Promise.all(chunks.map(summarizeChunk));
return summarizeChunk(partials.join("\n\n"));
}
This parallelizes well since each chunk call is independent, which keeps latency manageable even for large inputs. The tradeoff is that cross-chunk context (e.g., a theme that only becomes clear across the whole document) can get lost — if that matters, do a sequential pass where each chunk summary includes the running summary so far as context.
Streaming Summaries for Better Perceived Speed
For longer outputs (multi-paragraph summaries, not just 2-sentence ones), streaming improves perceived latency significantly because users see text appear immediately instead of waiting for the full response:
const stream = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"x-api-key": process.env.ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify({
model: "claude-sonnet-4-5",
max_tokens: 500,
stream: true,
messages: [{ role: "user", content: `Summarize:\n\n${longText}` }],
}),
});
You then read the response as server-sent events and append text chunks to the UI as they arrive.
Turning This Into a Production Endpoint
If you're building a summarization feature into a product — say, a "summarize this thread" button or a batch job that processes thousands of documents — you'll eventually need API keys scoped per application, usage tracking per customer, and a way to add team members without sharing one raw key. That's exactly what SubToAPI provides: it sits on top of your existing Claude access and gives you sub_live_... application keys, streaming support, tool use, and usage metadata in one dashboard, so you don't have to build that layer yourself.
A summarization call through SubToAPI looks like this:
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": 300,
"messages": [
{ "role": "user", "content": "Summarize in 3 bullet points:\n\n<text>" }
]
}'
Same prompt design principles apply — the request shape is compatible with the patterns above. See the quickstart to get a key, the messages docs for request details, and the streaming guide if you're building a live-updating UI. Plans start at €9/month on the pricing page, with a free trial at signup.
Questions
Does Claude API support summarizing PDFs or only plain text? The Messages API works with plain text and, depending on the model and endpoint, document inputs like PDFs. For custom formats (Word docs, HTML), extract the text first, then pass it through the same summarization prompt patterns shown here.
What's the best temperature setting for factual summaries? Keep it between 0 and 0.3. Lower temperatures reduce the chance Claude adds inferred details that weren't in the original text, which matters most for legal, medical, or support-ticket summarization.
How do I keep summarization costs predictable at scale? Cap max_tokens tightly, chunk long documents instead of sending oversized prompts repeatedly, and track usage per endpoint or customer. A proxy layer like SubToAPI's docs exposes usage metadata per request, which makes cost attribution straightforward without building custom logging.