Claude API: First Steps for Developers
AI generated
Claude
>_
Claude API · Anthropic · Messages API
Claude API: First Steps for Developers
From API key to first request

Using the Claude API productively takes more than an API key. This article walks through setting up an account and credentials, how the Messages API works with a system prompt, a messages array, and a model parameter, when streaming makes sense, and what a first working request looks like in PHP or JavaScript.

12 min. read API key · Messages API · Streaming PHP · JavaScript · cURL

1. What the Claude API is and when you need it

The Claude API is the programmatic interface to Anthropic's Claude models. While the web interface at claude.ai is built for interactive conversations, the API is aimed at developers who want to embed Claude into their own application, a backend script, or an automation: a PHP backend that generates product descriptions, a Node service that pre-classifies support tickets, or a CLI tool that summarizes log files all talk to the same REST endpoint. There is no graphical layer between the application and the model, only HTTP requests with JSON payloads.

The central endpoint is POST https://api.anthropic.com/v1/messages. Everything that happens with Claude programmatically goes through this one endpoint: simple chat requests, tool calls, image analysis, and structured outputs. There are no separate endpoints for different tasks. Getting started only requires understanding three things: how authentication works, how a request is structured, and how a response is processed. This article covers exactly those three points in practice, including runnable examples in PHP and JavaScript.

2. Creating an API key and securing credentials

An API key is created in the Anthropic Console (console.anthropic.com), inside a workspace that belongs to your organization. Every key is tied to an organization and optionally to a workspace, which allows separate budgets and permissions for different projects or teams. The key typically starts with sk-ant- and is shown in plain text only once. If you lose it, you have to create a new one and revoke the old one; there is no way to view it again afterward for security reasons.

The key never belongs directly in source code. The common practice is an environment variable, ANTHROPIC_API_KEY, which the official SDKs pick up automatically. In local projects the value lives in a .env file excluded from version control via .gitignore. In production, secret managers or the hosting provider's environment variables take over that job. A key committed to a repository is not a theoretical risk; automated scanners actively search public repositories for exactly this pattern.

Billing is usage-based per token, split into input and output tokens, and depends on the chosen model. Claude Haiku 4.5 is the cheapest and fastest model for simple tasks, Claude Sonnet 5 offers the best balance of speed and capability for most use cases, and Claude Opus 4.8 is the most capable model for complex tasks. A small amount of credit is enough for initial experiments, and the console shows current usage in real time.

3. The Messages API: system, messages, and model

Every request to /v1/messages needs at least three fields: model as the model identifier, max_tokens as the upper bound on response length, and messages as an array of alternating user and assistant turns. The first element in messages must have the role user, after which user and assistant alternate. Each message consists of role and content, where content can be either a plain string or an array of typed content blocks, for example for text, images, or files.

The system prompt is deliberately not part of the messages array, but its own top-level field. It defines the role, tone, and constraints for the entire conversation, for example "You are an assistant that only responds with valid JSON." This separation is not an implementation detail; it is structurally important. Simulating a system prompt as the first message in the messages array technically works, but it throws away the clean separation between behavioral instructions and conversation history and makes later prompt caching harder. Every request also needs the headers x-api-key, anthropic-version, and content-type: application/json.


{
  "model": "claude-opus-4-8",
  "max_tokens": 1024,
  "system": "You are a concise assistant for a German e-commerce team. Answer in German unless asked otherwise.",
  "messages": [
    { "role": "user", "content": "Write one sentence describing a red running shoe." }
  ]
}

// Response shape (abbreviated)
{
  "id": "msg_01abc...",
  "type": "message",
  "role": "assistant",
  "content": [
    { "type": "text", "text": "A lightweight red running shoe built for fast tempo runs." }
  ],
  "model": "claude-opus-4-8",
  "stop_reason": "end_turn",
  "usage": { "input_tokens": 28, "output_tokens": 14 }
}

4. Your first request: a minimal cURL example

The fastest way to test the Claude API without any dependencies is a single cURL call in the terminal. It lets you check whether the API key is set correctly and whether the request works at all before writing any code. This is also the first sensible step when debugging later integrations: if a PHP or Node script throws an error, the same cURL command with the same parameters clarifies within seconds whether the problem sits in your own code or in the request itself.

The response is a JSON object with a content array. Each block in it has a type, in the simplest case text with the actual response text. The stop_reason field shows why generation ended, usually end_turn for a naturally completed answer or max_tokens if the limit was hit before Claude finished. The usage object reports the actual input and output tokens consumed, important for cost control and for later tuning of max_tokens.


# Set the key once per shell session, never hardcode it in scripts
export ANTHROPIC_API_KEY="sk-ant-your-key-here"

curl https://api.anthropic.com/v1/messages \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-opus-4-8",
    "max_tokens": 256,
    "messages": [
      {"role": "user", "content": "What is the capital of Germany?"}
    ]
  }'

# Extract just the answer text with jq
response=$(curl -s https://api.anthropic.com/v1/messages \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{"model":"claude-opus-4-8","max_tokens":256,"messages":[{"role":"user","content":"Hello"}]}')

echo "$response" | jq -r '.content[0].text'

5. PHP example: calling the Claude API from a script

For PHP, Anthropic provides an official SDK, installable via composer require anthropic-ai/sdk. The SDK handles authentication, header construction, and error classification, so you do not need to set up your own HTTP client with Guzzle or cURL. The client reads the API key from the ANTHROPIC_API_KEY environment variable by default; an explicit parameter in the constructor is only needed when several keys are used in parallel, for example for different tenants in a multi-tenant application.

The SDK's response is a typed object whose content property is an array of polymorphic blocks. Before accessing ->text, the block type has to be checked, because a block can be of a different type, for example a thinking block when thinking is enabled. This type-checking pattern is not a PHP-specific detail; it runs through every official SDK and prevents a script from crashing with a fatal error when the response structure is unexpected.


<?php
declare(strict_types=1);

require __DIR__ . '/vendor/autoload.php';

use Anthropic\Client;

// The client reads ANTHROPIC_API_KEY from the environment automatically
$client = new Client();

$message = $client->messages->create(
    model: 'claude-opus-4-8',
    maxTokens: 512,
    system: 'You write short, factual product summaries in German.',
    messages: [
        ['role' => 'user', 'content' => 'Summarize a waterproof hiking backpack in two sentences.'],
    ],
);

// content is polymorphic - always check the block type before reading ->text
foreach ($message->content as $block) {
    if ($block->type === 'text') {
        echo $block->text . PHP_EOL;
    }
}

echo 'Tokens used: ' . $message->usage->outputTokens . PHP_EOL;

6. JavaScript example: a request from the server

In a Node.js environment, @anthropic-ai/sdk, installable via npm install @anthropic-ai/sdk, plays the same role as the PHP SDK. Important: the Claude API is called exclusively from the server side, never directly from browser JavaScript, because otherwise the API key would be visible in the client bundle and readable by every visitor. A typical setup is a small Express or Fastify endpoint that accepts the request, forwards it to Claude, and returns only the result to the frontend.

The JavaScript response structure matches PHP and cURL exactly, because every SDK mirrors the same JSON shape of the REST API, only with language-typical naming. A script run locally with node script.js is well suited for quickly testing prompts before integrating them into a larger application, for example an existing Node middleware or a Lambda handler.


import Anthropic from "@anthropic-ai/sdk";

// Reads ANTHROPIC_API_KEY from the environment automatically
const client = new Anthropic();

async function main() {
  const message = await client.messages.create({
    model: "claude-opus-4-8",
    max_tokens: 512,
    system: "You write short, factual product summaries in German.",
    messages: [
      { role: "user", content: "Summarize a waterproof hiking backpack in two sentences." },
    ],
  });

  // content is a discriminated union - narrow by .type before reading .text
  for (const block of message.content) {
    if (block.type === "text") {
      console.log(block.text);
    }
  }

  console.log(`Tokens used: ${message.usage.output_tokens}`);
}

main().catch((error) => {
  console.error("Request failed:", error.message);
  process.exit(1);
});

7. Streaming vs. non-streaming responses

By default a request waits until the complete response has been generated and only then returns a single JSON object. That is simple to process, but noticeably slow for users when responses are long, since they see nothing until the very last generated character. With "stream": true in the request, the API instead delivers a stream of server-sent events, so text appears as it is generated, just like in the claude.ai chat interface.

The event stream consists of several event types: message_start at the beginning, content_block_start and content_block_delta for each new piece of text, content_block_stop when a block finishes, message_delta with metadata such as stop_reason, and message_stop at the end. For a chat interface with a live display, streaming is almost always the right choice. A second, often overlooked rule: with a high max_tokens limit, roughly above 16,000 tokens, you should generally stream, because a non-streamed request risks an HTTP timeout during a long generation, regardless of whether the response is displayed live or not.


import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

async function streamAnswer() {
  const stream = client.messages.stream({
    model: "claude-opus-4-8",
    max_tokens: 1024,
    messages: [
      { role: "user", content: "Explain streaming responses in three short paragraphs." },
    ],
  });

  // Print text deltas as they arrive
  stream.on("text", (delta) => {
    process.stdout.write(delta);
  });

  // finalMessage() resolves once the stream completes, giving the full response
  const finalMessage = await stream.finalMessage();
  console.log(`\n\nTotal output tokens: ${finalMessage.usage.output_tokens}`);
}

streamAnswer();

8. Error handling, rate limits, and retries

The Claude API reports errors through HTTP status codes and a structured JSON error object. 400 means a malformed request, for example a missing required field, 401 means an invalid API key, 429 means an exceeded rate limit, and codes at or above 500 mean an error on Anthropic's side. Important for coding style: never catch errors by string-matching the error message, but through the typed exception classes every official SDK provides, for example RateLimitError or AuthenticationError in PHP and JavaScript.

Rate limits are capped per organization by requests per minute and tokens per minute and depend on your usage tier. On a 429 error, the retry-after header gives the recommended wait time in seconds. The official SDKs already retry 429 and 5xx errors automatically with exponential backoff, two retries by default, configurable on the client. For custom retry logic outside the SDKs, for example with raw HTTP calls, the same pattern applies: exponentially increasing wait time between attempts, an upper bound on the number of retries, and an immediate stop on 4xx errors that are not rate limits, since retrying there changes nothing.

Mironsoft

Claude API integration, AI-powered backends, and Magento automation

Ready to integrate Claude into your application?

We integrate the Claude API cleanly into existing PHP and Node applications, from the first request to production-ready workflows with streaming, error handling, and cost control.

API setup

Key management, model selection, and secure configuration for production

Backend integration

PHP and Node services with streaming, retries, and structured error handling

Magento & Hyva

Claude-powered modules for content, support, and product data

9. Beginner mistakes compared side by side

Most mistakes when starting out with the Claude API are structurally the same, whether you build with PHP, JavaScript, or plain cURL. The table below lines up the most common beginner mistakes against the recommended pattern.

Task Beginner mistake Recommended pattern Benefit
Storing the API key Key hardcoded in source code ANTHROPIC_API_KEY environment variable No leak via commits or screenshots
Setting behavior instructions Instruction as the first user message Top-level system field Clean separation, better caching
Reading the response content[0].text with no type check Check block.type before access No fatal error on a different block type
Long responses High max_tokens without streaming stream: true above roughly 16,000 tokens No HTTP timeout, immediate display
Rate limit (429) Resend immediately with no wait Respect retry-after, use backoff Fewer failed attempts, steadier throughput

None of these mistakes is hard to fix on its own, but combined they add up to an integration that works in testing and fails in production under load or during network hiccups. Applying the patterns from the table from the start saves larger refactors later.

10. Summary

Getting started with the Claude API always runs through the same basic building blocks: an API key from the Anthropic Console, stored securely as an environment variable, a request to /v1/messages with the fields model, max_tokens, and messages, and an optional but recommended system field for behavioral instructions. The official PHP and JavaScript SDKs handle authentication, error classification, and retry logic, so your own code can focus on the actual task instead of HTTP details.

Streaming is the right choice for interactive interfaces and for requests with a high max_tokens limit, while simple batch processing often does fine without it. Building in typed error handling, respecting rate limits, and cleanly separating the system prompt from the conversation history from the start avoids the most common pitfalls and gives you a foundation that scales to more complex use cases like tool use or structured outputs without a major rebuild.

Claude API for Developers: The Essentials at a Glance

API key & security

Key from the Anthropic Console, always stored as the ANTHROPIC_API_KEY environment variable, never in source code.

Messages API

Required fields model, max_tokens, messages. system as its own top-level field for behavior.

Streaming

stream: true for live interfaces and high max_tokens limits, otherwise non-streaming is fine.

PHP & JavaScript SDKs

Official SDKs handle auth, error classes, and automatic retries on 429/5xx.

11. FAQ: Claude API for Developers

1What is the Claude API and how does it differ from claude.ai?
The Claude API is the programmatic interface via /v1/messages with JSON requests. claude.ai is the interactive web interface for manual conversations. For your own applications, the API is always the right path.
2How do I get an API key?
In the Anthropic Console at console.anthropic.com. The key is shown in plain text only once and should be secured as an environment variable immediately.
3What does using the Claude API cost?
Usage-based per input and output token, depending on the model. Haiku 4.5 is cheapest, Sonnet 5 is the balance, Opus 4.8 is most capable. Usage shows in the console in real time.
4What is the difference between system and messages?
system is its own field for behavioral instructions, valid for the whole conversation. messages is the alternating history of user and assistant turns. The two should not be mixed.
5Which model should I choose to get started?
Opus 4.8 for the highest quality, Sonnet 5 as the default choice, Haiku 4.5 for simple, high-volume tasks. All three suit first experiments.
6When streaming instead of non-streaming?
For interactive interfaces with a live display, and above roughly 16,000 max_tokens to avoid timeouts. For simple batch processing, non-streaming is enough.
7How do I handle rate limits?
The retry-after header gives the wait time. SDKs retry 429/5xx automatically with backoff. Custom HTTP calls should implement the same pattern with increasing wait times.
8SDK or is cURL/Guzzle enough?
cURL is enough for tests. For production code the official SDKs are recommended, with built-in authentication, error classes, and retries.
9How do I secure the API key in PHP/Node?
As the ANTHROPIC_API_KEY environment variable, locally via .env and .gitignore, in production via a secret manager. Never in source code or the frontend bundle.
10What does stop_reason mean?
end_turn means naturally completed, max_tokens means the limit was reached, tool_use signals a requested tool call.