← Back to Blog
AIChatbotClaude APIBangkok

Building an AI Chatbot for Bangkok Clinics and Restaurants with Next.js and Claude

5 May 2026 · by Yunmin Shin

Why Build a Chatbot with Claude for a Bangkok Business?

A front desk at a Bangkok aesthetic clinic fields the same dozen questions all day: how much is a filler treatment, how long is downtime, do you take walk-ins, is there an English-speaking doctor. A restaurant discovery site gets the same pattern — is this place halal, is there parking, do they take reservations for groups of eight. None of that requires a human until the customer is ready to commit.

Claude's instruction-following and long context make it well suited to this: you can hand it a full treatment menu or restaurant listing as context and get answers that stay accurate to your actual pricing and policies, in whichever language the customer opens with. For a Bangkok business serving Thai locals, English-speaking expats, and — for clinics especially — Korean and Chinese medical tourists, that multilingual handling is the actual product, not a nice-to-have.

The pattern that works in production: the bot answers what it can from your real data, and hands off to a human on LINE the moment the conversation moves toward booking or payment. Claude answering FAQs at 2am and a staff member closing the actual sale on LINE the next morning is a division of labor that holds up.

How Do You Set Up the Claude API?

Install the Anthropic SDK:

npm install @anthropic-ai/sdk

Store the key server-side only:

ANTHROPIC_API_KEY=sk-ant-...
// lib/anthropic.ts
import Anthropic from "@anthropic-ai/sdk";
export const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

Never expose this key in client-side code. All calls must happen in Route Handlers, Server Actions, or server components — a chatbot widget embedded on a clinic's public site is exactly the kind of surface where a leaked key gets scraped and abused within hours.

How Do You Stream the Response?

Users on a mid-range Android phone over 4G notice the difference between a response that starts appearing after 400ms and one that arrives all at once after 4 seconds, even if the total time is similar. Use the Vercel AI SDK with the Anthropic provider:

npm install ai @ai-sdk/anthropic
// app/api/chat/route.ts
import { anthropic } from "@ai-sdk/anthropic";
import { streamText } from "ai";

export async function POST(req: Request) {
  const { messages } = await req.json();
  const result = streamText({
    model: anthropic("claude-sonnet-4-5"),
    system: CLINIC_SYSTEM_PROMPT,
    messages,
  });
  return result.toDataStreamResponse();
}

On the client, the useChat hook from ai manages message state and streaming with almost no boilerplate.

How Do You Write a System Prompt That Actually Knows Your Business?

The system prompt is where a generic chatbot becomes your chatbot. For a Bangkok clinic, it needs specifics, not vibes:

const CLINIC_SYSTEM_PROMPT = `You are the assistant for [Clinic Name], an aesthetic
clinic in [district], Bangkok. You answer questions about treatments, pricing tiers,
and downtime using ONLY the information in the treatment menu provided below.

Rules:
- Respond in the language the user writes in (Thai, English, or Korean).
- Never diagnose, recommend a specific treatment for a medical condition, or give
  a firm price for anything not listed — quote the listed price range and note
  final pricing is confirmed by the doctor at consultation.
- If the user wants to book, is asking about a specific date, or wants to discuss
  a photo they're sharing, say you're connecting them to staff and provide the
  LINE OA link: https://line.me/R/ti/p/@clinichandle
- Do not discuss competitors or make delivery/downtime guarantees beyond the
  ranges listed.

Treatment menu:
${treatmentMenuText}`;

That last rule — escalate on booking intent — is the one that matters most. Chatbots that try to complete bookings inline tend to produce awkward, error-prone conversations. LINE is where Thai customers actually expect to finalize a transaction with a real person.

How Do You Ground Answers in Real Treatment or Menu Data?

For a handful of services or a single menu, pasting the full text into the system prompt (as above) is simple and reliable — Claude's context window handles a few thousand words of treatment descriptions without difficulty. For a clinic running multiple locations with dozens of treatments and prices that change, pull the current menu from your database at request time instead of hardcoding it:

const treatments = await db.query("SELECT name, price_range, downtime FROM treatments WHERE active = true");
const menuText = treatments.map(t => `${t.name}: ${t.price_range}, downtime: ${t.downtime}`).join("\n");

This keeps the bot's answers synced with whatever the clinic manager last updated in the admin dashboard, rather than a stale prompt someone forgot to edit after a price change.

How Do You Maintain Conversation History and Control Cost?

Claude's API is stateless — you resend the full conversation on every request. useChat handles this client-side automatically. For persistence across sessions (a customer closes the tab and comes back), store messages in Supabase and reload the last 15–20 on return, which is enough context for a support conversation without inflating token cost.

Cost matters more than it first appears: a clinic's chatbot answering the same treatment questions dozens of times a day adds up. Capping conversation length, using a shorter model for simple FAQ deflection, and rate-limiting the endpoint per session all keep the bill predictable.

Ready to Build Something Fast?

Get a free quote. We reply within 24 hours.

Ready to build something fast and scalable?

Get a free project quote. We reply within 24 hours.

Get a Free Quote →