← Blog

Build a Customer Support Bot with Claude: Full Guide

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

Building a customer support bot with Claude means combining a well-scoped system prompt, a way to feed in your knowledge base or ticket context, and an API layer that handles streaming, retries, and authentication. Claude is well suited to this because it follows nuanced instructions reliably, handles long context (product docs, past tickets, order history) without losing track of details, and can be constrained to stay on-topic and refuse to hallucinate policy answers.

This guide walks through the actual architecture: how to structure the system prompt, how to pass in relevant context per conversation, how to stream replies to your frontend, and how to expose it as an API your app can call in production.

Core architecture

A Claude-powered support bot typically has four pieces:

  1. A system prompt that defines tone, scope, escalation rules, and what the bot is allowed to do (answer FAQs, look up orders, open tickets) versus what it must hand off to a human.
  2. A context injection step that pulls relevant docs, macros, or account data and puts them into the prompt before each turn (retrieval, not fine-tuning).
  3. The Claude API call itself, usually streaming, so the widget shows a typing effect instead of a long pause.
  4. A backend that manages conversation state, rate limits, and logging so you can review transcripts and improve the prompt over time.

None of this requires training a custom model. Claude answers based on the context you give it in each request.

Writing the system prompt

The system prompt is where most of the quality difference comes from. A vague prompt like "You are a helpful support agent" produces generic, occasionally wrong answers. A tight prompt produces consistent, on-brand behavior.

A reasonable starting structure:

You are the support assistant for Acme Cloud Storage.

Scope:
- Answer questions about billing, storage limits, file sharing, and account settings using ONLY the reference material provided below.
- If the answer isn't in the reference material, say you don't know and offer to escalate to a human agent.
- Never invent pricing, refund policies, or SLAs.

Tone: concise, friendly, no corporate filler phrases.

Escalation triggers: refund requests over €50, account deletion requests,
security incidents, angry customers repeating the same issue twice.
When triggered, respond with exactly: "ESCALATE: <reason>" as the first line.

The escalation marker is important in production — you parse it server-side and route the conversation to a human queue instead of showing "ESCALATE" to the customer.

Feeding in context (retrieval, not memory)

Claude doesn't know your product's return policy or a specific customer's order history unless you tell it. The common pattern is:

  1. On each incoming message, run a lightweight search (keyword or embedding-based) against your help center articles.
  2. Pull the top 2-4 relevant chunks.
  3. Insert them into the request as part of the user turn or a dedicated context block.
const contextBlock = relevantDocs.map(d => `### ${d.title}\n${d.body}`).join("\n\n");

const messages = [
  {
    role: "user",
    content: `Reference material:\n${contextBlock}\n\nCustomer question: ${userMessage}`
  }
];

Keep the retrieved context under a few thousand tokens per turn. More context isn't automatically better — irrelevant chunks can dilute the answer or get quoted incorrectly.

Making the API call

Whether you call Claude directly or through a proxy, the request shape is the same: a system prompt, a messages array, and a max_tokens limit. Here's a minimal example using SubToAPI's endpoint, which mirrors the standard messages format and adds an application-level API key, streaming, and usage metadata:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-3-5-sonnet",
    "system": "You are the support assistant for Acme Cloud Storage...",
    "max_tokens": 500,
    "messages": [
      {"role": "user", "content": "Reference material:\n...\n\nCustomer question: Why is my upload stuck at 90%?"}
    ]
  }'

If you're issuing your app its own key rather than sharing a raw Claude API key across environments, /docs/quickstart covers setup and /docs/messages covers the full request/response shape.

Streaming for a responsive widget

Support widgets feel broken if the customer stares at a blank bubble for three seconds. Streaming fixes that by sending tokens as they're generated:

const response = await fetch("https://api.subtoapi.app/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    model: "claude-3-5-sonnet",
    max_tokens: 500,
    stream: true,
    system: systemPrompt,
    messages
  })
});

const reader = response.body.getReader();
// forward each chunk to the frontend via SSE or websockets

Full details on the event format are in /docs/streaming.

Handling actions, not just answers

Real support bots often need to do things — look up an order, check subscription status, create a ticket. This is where tool use comes in: you define functions (like get_order_status(order_id)), Claude decides when to call them based on the conversation, and your backend executes the actual lookup and returns the result for Claude to summarize. This keeps the bot from guessing at data it doesn't have. /docs/tools covers the schema for defining and handling tool calls.

Deployment checklist

If you're running this across a team, a per-application key with usage tracking (rather than one shared secret pasted into every service) makes it much easier to see which surface — website widget, mobile app, internal admin tool — is driving cost. /pricing has details on seat-based plans if multiple people on your team need their own scoped keys.

questions

Do I need to fine-tune Claude for a support bot? No. Fine-tuning is rarely necessary. Retrieval — injecting relevant docs and account context into the prompt — handles the vast majority of support use cases and is far easier to update than a fine-tuned model.

How do I stop the bot from making up policies? Constrain it explicitly in the system prompt to only answer from provided reference material, and instruct it to say "I don't know" and escalate rather than guess. Testing with edge-case questions before launch catches most hallucination issues.

Can the bot actually resolve tickets, not just answer FAQs? Yes, using tool use: define functions for actions like checking order status or creating a ticket, let Claude call them mid-conversation, and execute the real logic on your backend. See /docs/tools for the request format.

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 →