Get Your Agent to Help
Install the official Claude API skill:
npx skills add anthropics/skills@claude-api
Then ask: "help me build the daily-digest run script using the Anthropic messages API"
Set Your Key
Get a key from console.anthropic.com:
export ANTHROPIC_API_KEY="sk-ant-..."
bun run sync
The Pattern
The messages endpoint — POST https://api.anthropic.com/v1/messages. Note the differences from OpenAI: x-api-key header (not Bearer), anthropic-version header required, response in data.content[0].text (not choices):
async function ask(prompt: string, system?: string): Promise<string> {
const resp = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.ANTHROPIC_API_KEY!,
"anthropic-version": "2023-06-01",
},
body: JSON.stringify({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
...(system ? { system } : {}),
messages: [{ role: "user", content: prompt }],
}),
});
if (!resp.ok) throw new Error(`Anthropic ${resp.status}: ${await resp.text()}`);
const data = (await resp.json()) as any;
return data.content[0].text;
}
The system parameter is a dedicated field (not a message role). Use it for your job's personality:
const digest = await ask(noteContent, "You summarize notes concisely. Use bullet points. End with action items.");
Current Models (March 2026)
| Model | Speed | Cost | Best For |
|---|---|---|---|
claude-haiku-4-5-20251001 | Fastest | Cheapest | High-volume classification, short tasks |
claude-sonnet-4-20250514 | Fast | Mid | Best default — follows instructions well |
claude-sonnet-4-5-20250929 | Fast | Mid | Extended thinking, newer capabilities |
claude-opus-4-20250514 | Slower | Highest | Complex analysis, long documents |
Start with claude-sonnet-4-20250514 for scheduled jobs. Drop to Haiku for high-frequency, simple tasks.
Also Consider: AI SDK
If you want a provider-agnostic layer, the Vercel AI SDK wraps both OpenAI and Anthropic:
npx skills add vercel/ai@ai-sdk
bun add ai @ai-sdk/anthropic
import { anthropic } from '@ai-sdk/anthropic';
import { generateText } from 'ai';
const { text } = await generateText({
model: anthropic('claude-sonnet-4-20250514'),
prompt: 'Summarize these notes...',
});
10.8K installs. The most popular AI skill in the ecosystem.
Test It
bun run src/cli.ts kick daily-digest
bun run src/cli.ts logs daily-digest
Companion Notes
Branch: Anthropic API
Direct API calls to Claude. Different API shape than OpenAI — messages API with explicit versioning.
Setup
export ANTHROPIC_API_KEY="sk-ant-..."
bun run sync
The Pattern
#!/usr/bin/env bun
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
if (!ANTHROPIC_API_KEY) {
console.error("[job] ANTHROPIC_API_KEY not set");
process.exit(1);
}
async function ask(prompt: string): Promise<string> {
const resp = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
},
body: JSON.stringify({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }],
}),
});
if (!resp.ok) {
const err = await resp.text();
throw new Error(`Anthropic ${resp.status}: ${err}`);
}
const data = (await resp.json()) as any;
return data.content[0].text;
}
Key Differences from OpenAI
- Header:
x-api-keyinstead ofAuthorization: Bearer - Version header:
anthropic-versionis required - Response shape:
data.content[0].textinstead ofdata.choices[0].message.content - No
max_tokensdefault: You must specify it or you get an error
Model Selection
| Model | Cost | Best For |
|---|---|---|
claude-sonnet-4-20250514 | Mid | Best default — fast, capable, good at following instructions |
claude-haiku-3-20240307 | Cheapest | Classification, short tasks, high volume |
claude-opus-4-20250514 | Highest | Complex analysis, long documents |
Start with Sonnet. Haiku for high-frequency jobs where cost matters.
System Prompts
Anthropic's API has a dedicated system parameter (not a message):
const resp = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: { /* ... */ },
body: JSON.stringify({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
system: "You are a note summarizer. Be concise. Use bullet points.",
messages: [{ role: "user", content: noteContent }],
}),
});
This is cleaner for scheduled jobs — the system prompt is your job's personality, the user message is the data.
Verification
# Test the API key
curl -s https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-sonnet-4-20250514","max_tokens":10,"messages":[{"role":"user","content":"Hi"}]}' | head -1
# Test through the job
bun run src/cli.ts kick daily-digest
bun run src/cli.ts logs daily-digest