← Blog

How to Build an AI Summarizer with the Claude API

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

Building an AI summarizer with the Claude API comes down to three decisions: how you structure the prompt, how you handle text that's longer than a single request should carry, and how you return results to your users. This guide walks through all three with working code, so you can go from "I want to summarize documents" to a deployed endpoint in an afternoon.

The core idea is simple: you send Claude the text you want summarized plus instructions about format and length, and it returns a summary. The complexity shows up when you deal with real-world inputs — meeting transcripts, support tickets, PDFs, long articles — that need consistent formatting, predictable length, and sometimes structured output rather than a paragraph of prose.

Minimal Working Example

Here's the smallest version that actually works in production, using the Messages API:

const response = await fetch("https://api.anthropic.com/v1/messages", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": process.env.ANTHROPIC_API_KEY,
    "anthropic-version": "2023-06-01",
  },
  body: JSON.stringify({
    model: "claude-sonnet-4-5",
    max_tokens: 500,
    messages: [
      {
        role: "user",
        content: `Summarize the following text in 3 bullet points. Be concise and avoid restating the intro.\n\n${text}`,
      },
    ],
  }),
});

const data = await response.json();
console.log(data.content[0].text);

This works fine for short inputs, but three things will break it once you have real users: inconsistent output format, long documents that exceed context comfortably, and no way to track how much you're spending per summary.

Designing a Prompt That Produces Consistent Summaries

The single biggest lever for summarizer quality is the prompt, not the model. A vague instruction like "summarize this" produces inconsistent length and tone across requests. Be explicit about:

A prompt template that works well for general-purpose summarization:

Summarize the following document for someone who has not read it.
Output format: a one-sentence headline, followed by 3-5 bullet points
covering the main claims or decisions. Do not include your own opinion
or add information not present in the text.

Document:
{{text}}

If you need machine-readable output — for a dashboard, a database field, or a downstream automation — ask for JSON explicitly and validate it on receipt:

Return only valid JSON matching this shape:
{"headline": string, "bullets": string[], "word_count": number}

Document:
{{text}}

Claude follows structured formatting instructions reliably, but always parse defensively — wrap JSON.parse in a try/catch and fall back to a re-prompt or an error state rather than crashing your pipeline.

Handling Long Documents

Claude's context window handles long inputs well, but "fits in context" and "summarizes well" aren't the same thing. Dumping a 40-page transcript into one prompt often produces a summary that over-indexes on the beginning or end of the document.

For anything beyond a few thousand words, use a map-reduce approach:

  1. Split the document into logical chunks (by section, by speaker turn, by page — not arbitrary character counts)
  2. Summarize each chunk independently
  3. Summarize the summaries into a final output
async function summarizeChunk(chunk) {
  // call Claude with a per-chunk prompt
}

async function summarizeLong(chunks) {
  const partials = await Promise.all(chunks.map(summarizeChunk));
  const combined = partials.join("\n\n");
  return summarizeChunk(
    `Combine these partial summaries into one coherent summary:\n\n${combined}`
  );
}

This is slower and costs more per document than a single call, but it produces noticeably better coverage of the full text. For most use cases, chunk by natural boundaries (paragraphs, sections) rather than fixed token counts — it keeps context coherent within each chunk.

Streaming for Better Perceived Speed

Summaries of any real length take a few seconds to generate. Streaming the response token-by-token makes the UI feel responsive instead of frozen. This matters more for summarizers than for chat, since users often stare at a loading spinner waiting for a wall of text to appear.

If you're building the summarizer on top of Claude directly, streaming means handling server-sent events and reassembling deltas client-side — a solid amount of plumbing for something that should be a small feature.

Turning This Into a Product Endpoint

If you're shipping this as a feature inside your own product — not just a script — you eventually need API key management per customer, usage tracking so you know what summarization is costing you, and rate limiting so one user can't burn through your budget. That's infrastructure most teams don't want to build themselves for a single feature.

This is where SubToAPI fits: it turns your Claude access into a proper HTTPS API with application-level sub_live_... keys, built-in streaming support, and per-key usage metadata, so you can issue a distinct key to each customer or environment without building an auth and billing layer from scratch. A summarizer endpoint looks the same as the example above, just pointed at SubToAPI's Messages endpoint:

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": 500,
    "messages": [{"role": "user", "content": "Summarize: ..."}]
  }'

Streaming responses for a snappier UI are covered in the streaming docs, and if you get to the point where the summarizer needs to pull live data (fetch a URL, query a database) before summarizing, that's a job for tool use rather than stuffing everything into one prompt. Setup takes a few minutes — see the quickstart — and plans start at Solo for individual projects, with Team and Scale tiers for shared usage across a company. Check pricing or start with a free trial at signup.

Questions

Do I need a specific Claude model for summarization? No single model is required. Smaller, faster models handle short documents well and cost less; larger models produce better summaries on long, nuanced, or technical text. Test both against your actual documents before committing.

How do I stop Claude from adding filler like "Here's a summary:"? Add an explicit instruction: "Do not include preamble or meta-commentary — output only the summary itself." This alone eliminates most unwanted framing text.

Can I summarize PDFs or scanned documents directly? You need to extract text first (via a PDF parser or OCR for scanned images) before sending it to Claude — the API summarizes text, not raw file bytes, so extraction quality directly affects summary quality.

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 →