← Blog

Claude API Integration with Python Flask: A Guide

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

Integrating the Claude API into a Flask application means setting up an HTTP client that sends requests to a messages endpoint, handling the JSON response (or a stream of events), and exposing that logic through your own Flask routes. This article walks through a working setup: installing dependencies, writing the request logic, handling streaming with server-sent events, and dealing with errors so your app doesn't crash on a bad API response.

If you're building a chatbot, internal tool, or any product feature that needs an LLM behind a Flask backend, the pattern is the same regardless of which Claude access method you use: you send a POST request with a model name, messages array, and max_tokens, then either read the full JSON response or consume a stream. The rest of this guide shows both approaches.

Setting Up Your Flask Project

Start with a minimal project structure:

mkdir claude-flask-app && cd claude-flask-app
python -m venv venv
source venv/bin/activate
pip install flask requests python-dotenv

Store your API key in a .env file rather than hardcoding it:

CLAUDE_API_KEY=your_api_key_here

Load it in your Flask app with python-dotenv, and never commit .env to version control.

A Basic Route That Calls the Claude API

Here's a simple /chat endpoint that accepts a user message and returns Claude's reply:

import os
import requests
from flask import Flask, request, jsonify
from dotenv import load_dotenv

load_dotenv()
app = Flask(__name__)

API_KEY = os.getenv("CLAUDE_API_KEY")
API_URL = "https://api.example.com/v1/messages"  # replace with your provider's endpoint

@app.route("/chat", methods=["POST"])
def chat():
    data = request.get_json()
    user_message = data.get("message", "")

    payload = {
        "model": "claude-sonnet-4",
        "max_tokens": 1024,
        "messages": [{"role": "user", "content": user_message}]
    }

    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    }

    response = requests.post(API_URL, json=payload, headers=headers, timeout=30)

    if response.status_code != 200:
        return jsonify({"error": response.text}), response.status_code

    result = response.json()
    return jsonify(result)

if __name__ == "__main__":
    app.run(debug=True, port=5000)

This pattern works whether you call Anthropic's API directly or route through a proxy like SubToAPI. If you're using SubToAPI, the only changes are the endpoint (https://api.subtoapi.app/v1/messages) and the key format (sub_live_...). The request and response shape follow the same conventions described in the messages docs, so existing Flask code needs almost no rewriting.

Handling Streaming Responses in Flask

For chat interfaces, streaming tokens as they arrive gives a much better user experience than waiting for the full response. Flask supports this with a generator function and the stream_with_context helper:

from flask import Response, stream_with_context
import json

@app.route("/chat/stream", methods=["POST"])
def chat_stream():
    data = request.get_json()
    user_message = data.get("message", "")

    payload = {
        "model": "claude-sonnet-4",
        "max_tokens": 1024,
        "stream": True,
        "messages": [{"role": "user", "content": user_message}]
    }

    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    }

    def generate():
        with requests.post(API_URL, json=payload, headers=headers, stream=True) as r:
            for line in r.iter_lines():
                if line:
                    yield f"{line.decode('utf-8')}\n\n"

    return Response(stream_with_context(generate()), mimetype="text/event-stream")

On the frontend, an EventSource or a fetch call reading the response body chunk by chunk will render tokens as they arrive. The exact event format depends on your API provider — see the streaming docs for the event structure if you're using SubToAPI, since it follows the same server-sent events pattern used across most Claude-compatible APIs.

Adding Tool Use to Your Flask Endpoint

If your Flask app needs Claude to call functions — looking up a database record, hitting an internal API, or running a calculation — you define tools in the request payload and handle the tool_use stop reason in your route:

payload = {
    "model": "claude-sonnet-4",
    "max_tokens": 1024,
    "tools": [
        {
            "name": "get_order_status",
            "description": "Look up an order status by order ID",
            "input_schema": {
                "type": "object",
                "properties": {"order_id": {"type": "string"}},
                "required": ["order_id"]
            }
        }
    ],
    "messages": [{"role": "user", "content": user_message}]
}

When the response comes back with stop_reason: "tool_use", your Flask code executes the requested function, then sends a follow-up request with the tool result appended to the messages array. Full request/response shapes for this flow are covered in the tools docs.

Why Use a Proxy Instead of Calling Anthropic Directly

Some teams call the Claude API directly with a personal or organization account. That works for prototypes, but it gets messy once you need per-application keys, usage tracking across services, or to give teammates access without sharing one shared secret. SubToAPI sits between your Flask app and your existing Claude access, giving you sub_live_... keys scoped per application, request logs, and team seats — without changing the request format your Flask routes already use. Setup takes a few minutes: create a key in the dashboard, drop it into your .env file, and point API_URL at https://api.subtoapi.app/v1/messages. Check the quickstart guide for the exact steps, or start a free trial at signup.

Error Handling Basics

At minimum, your Flask routes should handle:

Wrapping the API call in a small helper function keeps this logic out of your route handlers and makes it reusable across multiple endpoints.

Questions

Do I need a special Flask extension to use the Claude API? No. The requests library and Flask's built-in Response and stream_with_context are enough to handle both standard and streaming requests — no dedicated SDK is required.

Can I stream Claude responses to a browser from Flask? Yes. Use a generator function that yields chunks from the API response and return it as a text/event-stream Response object; the frontend consumes it with EventSource or a streaming fetch call.

What's the difference between calling Anthropic directly and using SubToAPI in a Flask app? The request and response format stay the same — only the base URL and key change. SubToAPI adds per-application API keys, usage visibility, and team seats on top of your existing Claude access, detailed in the pricing page.

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 →