Featured image for Claude API Tutorial: Getting Started with Anthropic (2026)
Tutorials ·
Beginner
· · 22 min read

Claude API Tutorial: Getting Started with Anthropic (2026)

Learn how to use the Claude API with Python in this step-by-step tutorial. From API key setup to your first working app with Anthropic's latest models.

ClaudeAnthropicAPIPythonTutorial

The first time I made a successful Claude API call, I was genuinely surprised. Three lines of Python, and I had an AI that actually followed my instructions—not just close enough, but exactly what I asked for. After wrestling with other AI APIs where “close enough” was the best I could hope for, Claude felt like a breath of fresh air.

If you’re looking to integrate Claude into your applications, you’re in the right place. This Claude API tutorial will take you from zero to a working application in about 30 minutes. We’ll cover everything from getting your API key to building a real code reviewer that you can actually use.

No fluff, no walls of theory. Just the practical stuff you need to start building.

Why Learn the Claude API?

Here’s the thing—there are a lot of AI APIs out there. So why Claude?

I’ve worked with most of them, and Claude consistently surprises me with how well it follows instructions. When I say “respond in exactly three bullet points,” I get three bullet points. Not two, not five with a bonus summary. Three.

Beyond instruction-following, here’s what makes Claude stand out:

  • Massive context window: 200,000 tokens. That’s roughly 150,000 words—enough to process entire books, lengthy codebases, or weeks of conversation history.
  • Serious coding chops: Claude Opus 4.5 hit 80.9% on SWE-bench Verified, making it the first AI to break the 80% barrier on real-world coding problems. According to Anthropic’s announcement, this represents a significant leap in AI coding capabilities.
  • Constitutional AI: Anthropic’s safety approach means Claude tends to be helpful without going off the rails.
  • Clean API design: If you’ve used OpenAI’s API, you’ll find Claude’s API refreshingly similar but with a few thoughtful improvements.

Is Claude better than ChatGPT for everything? No. But for tasks requiring precision, long context, or complex reasoning—it’s my go-to.

What Can You Build with Claude API?

The possibilities are honestly pretty broad, but here are some real applications I’ve seen built (or built myself):

Developer Tools

  • Code reviewers that catch bugs before they hit production
  • Documentation generators that actually understand your codebase
  • Automated PR summarizers for busy engineering teams
  • Test case generators that think about edge cases

Business Applications

  • Customer support chatbots that handle complex queries without escalation
  • Document analysis tools for legal contracts, research papers, or financial reports
  • Content generation pipelines that maintain brand voice
  • Data extraction from unstructured sources like PDFs and emails

Personal Projects

  • Research assistants that synthesize information from multiple sources
  • Writing tools that help with editing and brainstorming
  • Language learning companions with natural conversation
  • Custom automation workflows that require reasoning

The common thread? These are all tasks where you need an AI that can follow complex instructions, handle nuance, and work with substantial context. That’s Claude’s sweet spot.

Prerequisites and What You’ll Need

Before we dive in, let’s make sure you have everything ready. Nothing worse than getting excited to code and then realizing you’re missing something.

You’ll need:

  • Python 3.8 or higher — Check with python --version or python3 --version
  • Basic Python knowledge — Variables, functions, pip. Nothing fancy.
  • A code editor — VS Code, PyCharm, whatever you’re comfortable with
  • An Anthropic account — We’ll set this up in the next section
  • API credits — New accounts get trial credits, which should be plenty to follow along

Quick Python check:

python --version
# or
python3 --version

If you see something like Python 3.10.x or higher, you’re good. If not, grab the latest Python from python.org.

Getting Your Claude API Key

Time to get you set up with Anthropic. This part takes about 5 minutes.

Creating Your Anthropic Account

Head over to console.anthropic.com. You can sign up with email, Google, or GitHub—whatever’s fastest for you.

Here’s the process:

  1. Click “Sign Up” and create your account
  2. Verify your email (check spam if it doesn’t show up)
  3. Complete any onboarding steps Anthropic shows you
  4. Add a payment method or use the trial credits

New accounts typically get some trial credits to play with. That’s usually enough for a few thousand API calls while you’re learning.

Generating Your API Key

Once you’re in the console:

  1. Look for “API Keys” in the navigation (usually left sidebar)
  2. Click “Create Key”
  3. Give it a descriptive name like “my-first-project” or “learning-claude”
  4. Copy the key immediately

This is important: The API key is only shown once. The moment you navigate away, it’s gone. I’ve definitely made the mistake of closing the tab before copying. Don’t be me—copy it somewhere secure right now.

Security note: Never commit your API key to Git, share it publicly, or paste it into code that others might see. Treat it like a password.

Installing the Claude Python SDK

Let’s get the SDK installed. I’m going to show you the “do it right” way with a virtual environment, because I’ve learned the hard way that skipping this step leads to headaches later.

Step 1: Create a virtual environment

# Create a new directory for your project
mkdir claude-tutorial
cd claude-tutorial

# Create a virtual environment
python -m venv venv

# Activate it (macOS/Linux)
source venv/bin/activate

# Activate it (Windows)
venv\Scripts\activate

You should see (venv) appear in your terminal prompt. That means you’re in the virtual environment.

Step 2: Install the Anthropic SDK

pip install anthropic

That’s it. The package includes everything you need.

Step 3: Set up your API key

The cleanest way to handle your API key is with an environment variable. Create a file called .env in your project folder:

ANTHROPIC_API_KEY=sk-ant-api03-your-key-here

Then install python-dotenv to load it:

pip install python-dotenv

In your Python code, you’ll load it like this:

from dotenv import load_dotenv
load_dotenv()  # This loads the .env file

The Anthropic client automatically picks up the ANTHROPIC_API_KEY environment variable, so you don’t even need to pass it explicitly. Check the official Anthropic quickstart guide for more configuration options.

Step 4: Verify installation

import anthropic
print(anthropic.__version__)

If that prints a version number without errors, you’re ready to go.

Your First Claude API Call

Let’s write some actual code. This is the moment where it all comes together.

Basic Message Request

Create a file called hello_claude.py:

import anthropic
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

# Create the client
client = anthropic.Anthropic()

# Make your first API call
message = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Hello, Claude! What's something interesting about yourself?"}
    ]
)

# Print the response
print(message.content[0].text)

Run it:

python hello_claude.py

If everything is set up correctly, Claude will respond with something genuinely interesting. Congratulations—you just made your first Claude API call!

Understanding the Response

The response object contains more than just the text. Here’s what you’re working with:

print(f"Model: {message.model}")
print(f"Stop reason: {message.stop_reason}")
print(f"Input tokens: {message.usage.input_tokens}")
print(f"Output tokens: {message.usage.output_tokens}")
print(f"Response: {message.content[0].text}")

Breaking this down:

  • model: Which Claude model handled your request
  • stop_reason: Why Claude stopped generating (end_turn means it finished naturally)
  • usage: Token counts—important for tracking costs
  • content: The actual response, wrapped in a content block

The token usage is particularly useful. Every token costs money, and knowing how many you’re using helps you estimate costs before you accidentally burn through your credits. Ask me how I know.

Understanding Claude Models (Opus, Sonnet, Haiku)

Choosing the right model is actually a bigger deal than most tutorials make it out to be. Let me break down your options.

Model Comparison Table

ModelBest ForInput (per 1M tokens)Output (per 1M tokens)Speed
Claude Opus 4.5Complex reasoning, coding$5.00$25.00Slower
Claude Sonnet 4.5General tasks, balanced$3.00$15.00Medium
Claude Haiku 4.5High volume, simple tasks$0.80$4.00Fast

Claude Opus 4.5 — Maximum Intelligence

Opus is the heavyweight. It’s what you reach for when you need Claude at its absolute best: complex multi-step reasoning, intricate code generation, nuanced analysis of lengthy documents.

I use Opus for things like reviewing architecture decisions, debugging gnarly production issues, or analyzing research papers. It’s not cheap, but when you need the best, you need the best.

Claude Sonnet 4.5 — Balanced Performance

Sonnet hits the sweet spot for most tasks. It’s noticeably cheaper than Opus while still being remarkably capable. For most applications—chatbots, content generation, code assistance—Sonnet does the job well.

This is my default for development and testing. Good enough to validate ideas, cheap enough to iterate freely.

Claude Haiku 4.5 — Speed and Cost

Haiku is the surprise hit. It’s the fastest and cheapest, which sounds like a trade-off, but honestly? For a lot of tasks, Haiku is more than sufficient.

My hot take: Start with Haiku for development, even if you plan to use Opus in production. You’ll be surprised how often the cheaper model is good enough. And if it’s not, upgrading is just changing the model name.

When to Use Each Model — Practical Decision Guide

Let me share how I actually decide which model to use for different tasks. This isn’t theoretical—it’s what I’ve learned from running up API bills and comparing results.

Use Claude Opus 4.5 when:

  • You’re debugging complex, multi-file issues where context matters
  • The task requires reasoning across many steps (planning, research synthesis)
  • You need the highest quality output and cost isn’t the primary concern
  • You’re working with nuanced content that requires careful understanding
  • The output will be customer-facing or high-stakes

Use Claude Sonnet 4.5 when:

  • You need good quality at reasonable cost (most production workloads)
  • The task is important but not mission-critical
  • You’re building chatbots or interactive applications
  • Response quality matters but you’re watching costs
  • You’re not sure which model to use (Sonnet is a safe default)

Use Claude Haiku 4.5 when:

  • Speed is critical (real-time applications, autocomplete)
  • You’re processing high volumes of simple requests
  • The task is straightforward (classification, simple Q&A)
  • You’re in development and iterating quickly
  • Cost efficiency is your top priority

Here’s a pattern I follow: start with Haiku for development, test with Sonnet for integration, and only upgrade to Opus where testing reveals quality gaps that matter for your use case.

To use a different model, just swap the model parameter:

# Use Haiku for cost-effective operations
message = client.messages.create(
    model="claude-haiku-4-5-20251015",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Summarize this briefly."}]
)

Working with the Messages API

Now that you’ve got the basics, let’s explore what makes the Messages API powerful.

Message Structure and Roles

Claude’s API uses a simple but flexible conversation structure. Every message has a role (user or assistant) and content:

messages = [
    {"role": "user", "content": "What's the capital of France?"},
    {"role": "assistant", "content": "The capital of France is Paris."},
    {"role": "user", "content": "What's the population?"}
]

message = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=messages
)

This is how you build multi-turn conversations. Each message builds context for the next response. Claude uses the entire conversation history to inform its answers.

System Prompts for Control

System prompts let you set the behavior and personality of Claude before the conversation starts. Think of it as giving Claude its “role” or “constraints.”

message = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    system="You are a senior Python developer. Review code carefully, explain issues clearly, and suggest improvements. Be direct but friendly.",
    messages=[
        {"role": "user", "content": """
        Review this code:
        
        def calc(x,y):
            return x+y
        """}
    ]
)

System prompts are powerful. I’ve seen the same API call produce dramatically different results just by tweaking the system prompt. It’s worth spending time on this—a good system prompt is often the difference between a mediocre application and a great one.

If you’re interested in taking this further, check out how AI agents use system prompts to create specialized behaviors.

Controlling Output (Temperature, Max Tokens)

Two parameters you’ll use all the time:

Temperature controls randomness:

  • 0.0 = Deterministic. Same input, same output. Great for coding tasks.
  • 1.0 = Creative. More varied responses. Good for brainstorming.

Max tokens limits response length:

  • Set this based on what you expect. Short answers? 256. Long explanations? 2048 or more.
message = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=256,
    temperature=0.0,  # Deterministic for coding
    messages=[{"role": "user", "content": "Write a Python function to reverse a string."}]
)

Advanced Features

Once you’re comfortable with the basics, these features will level up your applications.

Streaming Responses

For long responses, streaming provides a much better user experience. Instead of waiting for the entire response, you get tokens as they’re generated:

with client.messages.stream(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain quantum computing in detail."}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

This is essential for chatbots or any interface where users are waiting. Nobody wants to stare at a loading spinner for 10 seconds.

Pro tip: When streaming, you can also handle the complete response at the end. The stream object gives you access to the final message after iteration completes:

with client.messages.stream(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain quantum computing in detail."}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
    # After streaming, get the complete message
    final_message = stream.get_final_message()
    print(f"\n\nTotal tokens: {final_message.usage.output_tokens}")

Vision and Image Input

Claude can analyze images. Pass them as base64 or URLs. This capability opens up applications that just weren’t possible with text-only models—think document processing, UI analysis, chart interpretation, or even meme explanation (yes, really).

import base64

def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        return base64.standard_b64encode(image_file.read()).decode("utf-8")

message = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": encode_image("screenshot.png"),
                    },
                },
                {
                    "type": "text",
                    "text": "What do you see in this image?"
                }
            ],
        }
    ],
)

I’ve used this for everything from analyzing UI screenshots to extracting data from charts. It’s surprisingly capable.

Vision use cases that work well:

  • Screenshot-based bug reports where you need to understand visual context
  • Data extraction from charts and infographics
  • Document layout analysis (understanding where text appears)
  • Image-based Q&A (describing what’s in photos)
  • Comparing visual designs or detecting differences

Limitations to be aware of:

  • Claude can’t generate images (that’s a different capability)
  • Very small text in images may be hard to read clearly
  • Complex technical diagrams might need clearer images
  • Processing multiple images increases token usage significantly

Tool Calling (Function Calling)

Tool calling lets Claude decide when to use external functions. You define the tools, and Claude determines when they’re appropriate:

tools = [
    {
        "name": "get_weather",
        "description": "Get the current weather for a location",
        "input_schema": {
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "City name"},
            },
            "required": ["location"]
        }
    }
]

message = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "What's the weather in Tokyo?"}]
)

This is how you build things like RAG chatbots that can search databases or fetch real-time information.

How tool calling works under the hood:

When you define tools, Claude analyzes the user’s request and decides whether any tool is needed. If so, it returns a response indicating which tool to call and with what parameters. Your code then executes the tool and sends the results back to Claude for a final response.

Here’s the complete flow:

  1. User asks a question that might need a tool
  2. Claude decides if a tool is helpful and which one
  3. Your code receives a tool_use response with function name and arguments
  4. You execute the function with those arguments
  5. You send the tool result back to Claude
  6. Claude generates a final response using the tool result

This pattern is powerful for building agents that can interact with external systems, databases, APIs, or any capability you can wrap in a function. The key is writing clear tool descriptions so Claude knows when each tool is appropriate. For ready-to-use code examples, check our Claude API code snippets collection.

Error Handling and Best Practices

Let’s talk about what happens when things go wrong—because they will.

Common Errors and Solutions

Here’s what you’ll encounter and how to handle it:

import anthropic
from anthropic import APIError, RateLimitError, AuthenticationError

try:
    message = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello!"}]
    )
except AuthenticationError:
    print("Invalid API key. Check your ANTHROPIC_API_KEY.")
except RateLimitError:
    print("Rate limit hit. Slow down or implement retry logic.")
except APIError as e:
    print(f"API error: {e.message}")

Rate limits exist to save you from yourself. Ask me how I know. I once had a bug in a loop that made thousands of requests in seconds. My credit balance did not appreciate it.

Understanding Rate Limits in Detail

Rate limits aren’t just about requests per minute—Claude’s rate limiting is actually more nuanced. Here’s what you need to know:

Token-based limits: Claude limits both requests per minute AND tokens per minute. You might hit token limits before request limits if you’re sending large prompts.

Check the headers: Every response includes rate limit information in the headers:

  • anthropic-ratelimit-requests-limit: Max requests allowed per interval
  • anthropic-ratelimit-requests-remaining: How many requests you have left
  • anthropic-ratelimit-tokens-limit: Max tokens allowed per interval
  • anthropic-ratelimit-tokens-remaining: How many tokens you can still use

Tier-based limits: Your rate limits depend on your usage tier with Anthropic. Higher spend = higher limits. If you’re building something serious, you can request limit increases through the console.

Debugging Common Issues

When things break (and they will), here’s my troubleshooting checklist:

Authentication failures:

  • Did you copy the full API key? Easy to miss characters
  • Is the environment variable actually set? Print it (safely) to check
  • Did the key get committed somewhere and get revoked?

Unexpected responses:

  • Check your system prompt—is it too long? Too vague?
  • Is your temperature setting appropriate for the task?
  • Are you hitting max_tokens limits and getting cut-off responses?

Slow responses:

  • Large context = slower responses. Reduce context if possible
  • Consider streaming for better perceived performance
  • Opus is slower than Sonnet, Sonnet is slower than Haiku

Costs running higher than expected:

  • Check your token usage carefully—output tokens cost more
  • Large system prompts add up across many requests
  • Consider prompt caching for repeated prompts

Production Best Practices

When you’re ready for production:

  1. Never hardcode API keys. Environment variables, always.
  2. Implement retry logic with exponential backoff for rate limits.
  3. Log everything — requests, responses, errors. You’ll thank yourself later.
  4. Monitor token usage — set up alerts before you hit unexpected costs.
  5. Use async for high throughput — the SDK supports it.
import asyncio
from anthropic import AsyncAnthropic

async def call_claude_async():
    client = AsyncAnthropic()
    message = await client.messages.create(
        model="claude-haiku-4-5-20251015",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello!"}]
    )
    return message.content[0].text

# Run it
result = asyncio.run(call_claude_async())
print(result)

Real-World Example — Building a Code Reviewer

Let’s build something practical: an AI code reviewer that gives you feedback on Python code.

import anthropic
from dotenv import load_dotenv

load_dotenv()

def review_code(code: str) -> str:
    """
    Send code to Claude for review and get structured feedback.
    """
    client = anthropic.Anthropic()
    
    system_prompt = """You are a senior Python developer conducting a code review.
    Analyze the code for:
    1. Bugs or potential issues
    2. Code style and readability
    3. Performance concerns
    4. Security vulnerabilities
    5. Suggestions for improvement
    
    Be constructive and specific. Include code examples for suggested fixes.
    Format your response with clear sections."""
    
    message = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=2048,
        temperature=0.0,
        system=system_prompt,
        messages=[
            {
                "role": "user",
                "content": f"Please review this Python code:\n\n```python\n{code}\n```"
            }
        ]
    )
    
    return message.content[0].text

# Example usage
sample_code = '''
def get_user(id):
    import sqlite3
    conn = sqlite3.connect('users.db')
    cursor = conn.cursor()
    cursor.execute(f"SELECT * FROM users WHERE id = {id}")
    return cursor.fetchone()
'''

print(review_code(sample_code))

This will catch some interesting issues in that sample code—SQL injection vulnerability, missing connection cleanup, and more.

What Claude will typically catch in that example:

  • SQL injection vulnerability (the f-string formatting is dangerous)
  • Missing finally block or context manager for database cleanup
  • Import inside function (less efficient)
  • Vague parameter name (id instead of user_id)
  • Missing error handling for database operations

You can extend this code reviewer in interesting ways:

  • Add file reading to review entire files
  • Track issues across a codebase
  • Generate fix suggestions automatically
  • Integrate with Git hooks for pre-commit reviews
  • Connect to your CI/CD pipeline

The key insight is that once you have Claude analyzing code, you can build increasingly sophisticated tooling around it. Start simple, prove it works, then add complexity.

Want to take this further? Check out AI agent frameworks for building more sophisticated code analysis tools, or explore our Claude agents library for pre-built agent templates.

Claude API Pricing Guide (January 2026)

Let’s talk money. Understanding costs helps you build sustainable applications.

Current Pricing

ModelInput (per 1M tokens)Output (per 1M tokens)
Claude Opus 4.5$5.00$25.00
Claude Sonnet 4.5$3.00$15.00
Claude Haiku 4.5$0.80$4.00

Batch processing gives you 50% off these rates if you can wait for asynchronous processing.

Prompt caching can save up to 90% on repeated prompts—worth exploring for production apps.

Cost Estimation

A rough calculation: 1 million tokens is about 750,000 words of text. For a typical chatbot:

  • User message: ~100 tokens
  • System prompt: ~300 tokens
  • Claude response: ~500 tokens

At Haiku prices, 1,000 conversations would cost roughly $0.80 + $2.00 = $2.80. That’s… pretty affordable.

Word of caution: These prices are current as of January 2026, but Anthropic updates pricing regularly. Always check Anthropic’s official pricing page before budgeting serious projects.

Frequently Asked Questions

Is the Claude API free to use?

Not entirely, but new accounts get trial credits to start. After that, it’s pay-as-you-go. There’s no monthly subscription for API access—you only pay for what you use. Claude Haiku is affordable enough that experimentation won’t break the bank.

What’s the difference between Claude and ChatGPT API?

Both are powerful, but they have different strengths. Claude excels at following complex instructions precisely and has a larger context window (200K vs 128K). ChatGPT has broader tool integrations and a more established ecosystem. In my experience, Claude produces cleaner, more consistent responses for structured tasks.

How do I handle rate limits in Claude API?

Implement retry logic with exponential backoff. Start with a 1-second delay, then double it with each retry (1s, 2s, 4s, etc.). The response headers include rate limit information—check anthropic-ratelimit-tokens-remaining to monitor usage.

Can I use Claude API for commercial projects?

Yes. Anthropic’s API terms allow commercial use. Just review their usage policies to ensure your use case is compliant—there are restrictions around harmful applications, but standard business uses are fine.

What is the Claude API context window?

Claude supports 200,000 tokens in its context window. That’s roughly 150,000 words—enough to process multiple long documents, extensive conversation history, or large codebases in a single request.

How do I keep my API key secure?

Use environment variables, never commit keys to version control, and consider using a secrets manager in production. Rotate keys periodically, and set up alerts to detect unusual API usage patterns.

Wrapping Up

You’ve gone from zero Claude experience to building a working code reviewer. Not bad for one tutorial.

Here’s what you now know:

  • How to get set up with an Anthropic account and API key
  • Making basic and advanced API calls
  • Choosing the right model for your use case
  • Handling errors like a pro
  • Building practical applications

The Claude API is genuinely enjoyable to work with. The responses are consistent, the documentation is solid, and the developer experience just… works.

Common Next Steps After This Tutorial

Based on what I see developers do after learning the basics, here are some natural directions to explore:

Level up your prompting: The difference between okay results and great results often comes down to how you craft your prompts, especially system prompts. Spend time experimenting with different approaches.

Build something real: The best way to learn is by building. Pick a problem you actually have—maybe automating something tedious, or building a tool you’d use daily—and use Claude to solve it.

Explore multi-turn conversations: Building chatbots or assistants that maintain context across many turns opens up a lot of possibilities. The Messages API structure makes this natural.

Try tool calling for real: If you have APIs or databases you work with, connecting Claude to them via tool calling is incredibly powerful. Start with one simple tool and expand from there.

What to do next:

  1. Build something with what you learned
  2. Experiment with different models
  3. Check out our AI agents guide for more advanced patterns

Now go build something cool.

Found this helpful? Share it with others.

Vibe Coder avatar

Vibe Coder

AI Engineer & Technical Writer
5+ years experience

AI Engineer with 5+ years of experience building production AI systems. Specialized in AI agents, LLMs, and developer tools. Previously built AI solutions processing millions of requests daily. Passionate about making AI accessible to every developer.

AI Agents LLMs Prompt Engineering Python TypeScript