← Blog

Claude API Tutorial: Build Your First Integration

2026-08-31 · 5 min read · SubToAPI Team

If you're searching for a Claude API tutorial, you probably want one thing: working code that sends a request to Claude and gets a response back, followed by enough context to build something real on top of it. This tutorial walks through authentication, the Messages endpoint, streaming responses, and tool use, with code you can copy and run.

By the end, you'll have made your first Claude API call, streamed a response token by token, and given Claude a tool it can call. We'll use plain HTTP requests so the concepts transfer regardless of which SDK or language you end up using.

What You Need Before Starting

You need an API key and a way to send authenticated HTTPS requests. Two paths get you there:

  1. Direct Anthropic API access — requires a separate billing account, credit-based pricing, and its own console for key management.
  2. A wrapper like SubToAPI — if you already have Claude access through a subscription, SubToAPI turns it into a standard HTTPS API with an sub_live_... key, so you skip setting up separate API billing. The request format below is nearly identical either way.

This tutorial uses the SubToAPI endpoint format, but the JSON structure matches the Messages API convention, so the concepts apply broadly.

Step 1: Make Your First Request

Every Claude API call needs three things: a model name, a max_tokens limit, and a messages array. Here's the minimal request:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "Explain what a race condition is in one paragraph."}
    ]
  }'

The response comes back as JSON with the assistant's reply in a content array, plus a usage object showing input and output token counts. That usage data matters for cost tracking — see the messages docs for the full response schema.

Step 2: Add a System Prompt and Conversation History

Real applications rarely send a single message. You'll usually want a system prompt to set behavior, and a growing messages array to maintain conversation state:

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-sonnet-4",
    max_tokens: 1024,
    system: "You are a terse code reviewer. Point out bugs only, no praise.",
    messages: [
      { role: "user", content: "Review this: function add(a,b){return a+b}" },
      { role: "assistant", content: "No bugs found. Consider adding type checks." },
      { role: "user", content: "What about negative numbers?" }
    ]
  })
});

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

Note that the API is stateless — you're responsible for resending prior turns each time. Most production apps store conversation history in a database and reconstruct the messages array per request.

Step 3: Stream Responses

For anything user-facing, streaming matters. Without it, users stare at a blank screen until the full response is ready. With streaming, tokens appear 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-sonnet-4",
    max_tokens: 1024,
    stream: true,
    messages: [{ role: "user", content: "Write a haiku about compilers." }]
  })
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  process.stdout.write(decoder.decode(value));
}

The stream sends server-sent events with incremental content deltas. Parsing them properly (handling content_block_delta events, tracking indices for multiple content blocks) is covered in more depth in the streaming docs — the event types are the same whether you're calling Anthropic directly or through a wrapper.

Step 4: Give Claude a Tool

Tool use (sometimes called function calling) lets Claude request that your code run something — a database lookup, a calculator, a web search — and then incorporate the result into its answer. You define tools with a JSON schema:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4",
    "max_tokens": 1024,
    "tools": [
      {
        "name": "get_weather",
        "description": "Get current weather for a city",
        "input_schema": {
          "type": "object",
          "properties": {
            "city": {"type": "string"}
          },
          "required": ["city"]
        }
      }
    ],
    "messages": [
      {"role": "user", "content": "Should I bring an umbrella in Lisbon today?"}
    ]
  }'

When Claude decides it needs the tool, the response includes a tool_use block with the input it wants to send. Your code runs the actual function, then sends the result back in a follow-up message with a tool_result block. Claude then produces the final answer. Full request/response shapes are in the tool use docs.

Step 5: Handle Errors and Rate Limits

Production code needs to handle non-200 responses gracefully — rate limits (429), invalid requests (400), and server errors (500+) all need different handling:

if (!response.ok) {
  if (response.status === 429) {
    // back off and retry
  } else {
    const error = await response.json();
    console.error("API error:", error.error?.message);
  }
}

A basic exponential backoff on 429s and 5xxs will cover most transient failures without over-engineering your retry logic.

Putting It Together

A typical minimal integration looks like: accept user input → append to stored conversation → send to /v1/messages with streaming enabled → pipe deltas to the frontend → append the final assistant message back to storage. From there, tool use and system prompts layer on top without changing that core loop.

If you want to skip the billing and key management setup and get a working sub_live_... key in minutes, sign up for a free trial — the quickstart guide walks through the same steps above with copy-paste examples, and pricing is a flat per-seat rate rather than usage-based billing.

FAQ

Do I need an Anthropic account to follow this tutorial? No. The request format shown works against any endpoint implementing the same Messages API shape, including wrappers like SubToAPI that issue their own API keys.

What's the difference between streaming and non-streaming responses? Non-streaming waits for the full response before returning JSON. Streaming sends incremental chunks via server-sent events, letting you display partial output as it's generated — essential for chat-style UIs.

Can I use this tutorial's code with the official Anthropic SDK? The JSON request and response structure matches, so the concepts (messages array, system prompt, tool_use blocks) transfer directly, though exact endpoint URLs and headers depend on which service you're calling.

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 →