BranchProvider: Anthropic API

Provider: Anthropic API

Claude's messages API — system prompts, structured output.

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)

ModelSpeedCostBest For
claude-haiku-4-5-20251001FastestCheapestHigh-volume classification, short tasks
claude-sonnet-4-20250514FastMidBest default — follows instructions well
claude-sonnet-4-5-20250929FastMidExtended thinking, newer capabilities
claude-opus-4-20250514SlowerHighestComplex 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-key instead of Authorization: Bearer
  • Version header: anthropic-version is required
  • Response shape: data.content[0].text instead of data.choices[0].message.content
  • No max_tokens default: You must specify it or you get an error

Model Selection

ModelCostBest For
claude-sonnet-4-20250514MidBest default — fast, capable, good at following instructions
claude-haiku-3-20240307CheapestClassification, short tasks, high volume
claude-opus-4-20250514HighestComplex 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