# claude-api
Type-safe Rust client for the [Anthropic API](https://docs.anthropic.com/).
Sibling project to `claude-wrapper`. That one wraps the `claude` CLI; this
one wraps the HTTP API. They do not depend on each other.
## Status
**v0.5 -- full API surface.** Every documented Anthropic endpoint is
now reachable through a typed Rust namespace:
- **Messages, Models, Batches, Files, count_tokens, streaming**
(carried forward from v0.1-v0.4)
- **Admin API** (27 endpoints): organization, invites, users,
workspaces + members, api_keys, usage_report, cost_report,
rate_limits
- **Skills API** (8 endpoints): full CRUD + skill versions, multipart
upload
- **User Profiles API** (5 endpoints) including the enrollment-URL flow
- **Managed Agents preview**: sessions, agents, environments, vaults
+ credentials, memory_stores + memories + memory_versions, session
resources, events (list/send/SSE stream), and the multi-agent
threads endpoints
- **Bedrock auth** via a sigv4 `RequestSigner` extension point
- **Typed `BetaHeader` enum** for the 23 canonical `anthropic-beta`
values, with `Other(String)` forward-compat fallthrough
- **Live-test harness** with 15 record-or-replay tests covering the
cheap and read-only surfaces; cassettes committed for free CI replay
- **Spec-diff tooling** that compares every public Rust struct to its
OpenAPI schema field-by-field
Carried forward from v0.4 and earlier:
- **v0.4** Agent-loop guardrails (parallel dispatch + cost budget +
cancellation), streaming callbacks, `dry_run`, `cost_preview`,
`#[derive(Tool)]` proc macro
- **v0.3** Typed `Citation` enum, context compaction, full Batches
API, Files API beta, typed `BuiltinTool` wrappers
- **v0.2** `ToolRegistry` + agent loop, `Conversation` helper,
`PricingTable`, vision and document blocks, prompt-cache sugar,
sync feature
- **v0.1** Messages + Models endpoints, forward-compatible serde,
retry policy that honors `Retry-After`, `request-id` propagation,
structured `tracing`
See [`CHANGELOG.md`](CHANGELOG.md) for per-version detail.
## Quick start
```toml
[dependencies]
claude-api = "0.5"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```
```rust
use claude_api::{Client, messages::CreateMessageRequest, types::ModelId};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new(std::env::var("ANTHROPIC_API_KEY")?);
let resp = client
.messages()
.create(
CreateMessageRequest::builder()
.model(ModelId::SONNET_4_6)
.max_tokens(256)
.system("Be concise.")
.user("What is the capital of France?")
.build()?,
)
.await?;
for block in &resp.content {
if let claude_api::messages::ContentBlock::Known(
claude_api::messages::KnownBlock::Text { text, .. },
) = block
{
println!("{text}");
}
}
Ok(())
}
```
See [`examples/`](examples/) for streaming, streaming-with-callbacks,
tool use, derived tools, vision, document, conversation, and the agent
loop.
## Why another Anthropic Rust client?
- **Forward-compatible by design.** New `ContentBlock`, `StreamEvent`,
`ContentDelta`, `Citation`, and `BuiltinTool` variants from the API are
preserved as raw JSON via an `Other(Value)` arm rather than breaking
older SDK versions. New `type` tags round-trip byte-for-byte. No other
Rust crate (and no official SDK in any language) does this.
**Upgrade contract**: when a server-side `type` tag that previously
fell through to `Other` becomes a recognized `Known` variant in a new
release, that's a **minor** version bump. Code that pattern-matched
on `Other(v) if v["type"] == "thinking"` will silently stop matching
-- the value now arrives as `Known(KnownBlock::Thinking { .. })`.
When you bump claude-api, sweep your `Other` matches and route the
newly-known variants explicitly. Releases that promote variants will
call them out in the changelog.
- **`Retry-After` honored.** Most existing Rust crates for the Anthropic
API ignore the header. This one respects it, with configurable
`RetryPolicy { max_attempts, initial_backoff, max_backoff, jitter,
respect_retry_after }`.
- **Cost-aware by default.** `PricingTable` ships with bundled rates for
current models; `Conversation::cost(&PricingTable)` and
`cost_preview(&request, &pricing)` give you live and pre-flight USD
numbers. Agent loop accepts a `cost_budget` that aborts a run before
the next iteration if a cap is exceeded.
- **Operational quality from day one.** `request-id` is surfaced on every
error (critical for support tickets), `ApiKey: Debug` redacts the
secret, base-URL override makes wiremock-based testing the default
story, structured `tracing` spans on every request and retry.
- **Tools you can derive.** `#[derive(Tool)]` on a struct generates the
`Tool` impl from the struct's `JsonSchema` and an inherent
`async fn run(self)`. No string-literal schemas, no boilerplate `name`
/ `description` overrides unless you want them.
- **No surprise abstractions.** No prompt-template DSL, no multi-provider
routing, no response caching, no bundled CLI. If you want those, use a
different crate.
## Feature flags
| `async` | yes | Async client (tokio + reqwest) |
| `rustls` | yes | rustls TLS backend |
| `streaming` | yes | SSE streaming + `EventStream::aggregate` + callback hooks |
| `sync` | | Blocking client (reqwest blocking) |
| `native-tls` | | native-tls backend instead of rustls |
| `schemars-tools` | | `Tool::from_schemars::<T: JsonSchema>` ctor |
| `derive` | | `#[derive(Tool)]` (pulls in `claude-api-derive`) |
| `pricing` | | `PricingTable` + cost calculation + `cost_preview` |
| `conversation` | | Multi-turn `Conversation` helper |
| `bedrock` | | AWS sigv4 `BedrockSigner` (custom auth signer) |
| `vertex` | | GCP Vertex auth -- v0.6+ (placeholder; not wired yet) |
| `admin` | | Admin API (organizations, users, workspaces, etc.) |
| `skills` | | Skills API (CRUD + versions, multipart upload) |
| `user-profiles` | | User Profiles API + enrollment-URL flow |
| `managed-agents-preview` | | Managed Agents preview (sessions, agents, vaults, ...) |
Disable defaults if you only want the type definitions:
```toml
claude-api = { version = "0.5", default-features = false }
```
## Tool example with `#[derive(Tool)]`
```rust
use claude_api::derive::Tool;
use claude_api::tool_dispatch::{ToolError, ToolRegistry};
use schemars::JsonSchema;
use serde::Deserialize;
use serde_json::{json, Value};
/// Get the current weather for a city.
#[derive(Deserialize, JsonSchema, Tool)]
struct GetWeather {
/// City to look up.
city: String,
}
impl GetWeather {
async fn run(self) -> Result<Value, ToolError> {
Ok(json!({"temp_f": 72, "city": self.city}))
}
}
let mut registry = ToolRegistry::new();
registry.register_tool(GetWeather::tool());
```
The tool name (`get_weather`) is derived from the struct name; the
description from the doc comment. Override either with
`#[tool(name = "...", description = "...")]`.
## Roadmap
- **v0.1** Messages, Models, streaming, retry, forward-compat
- **v0.2** `ToolRegistry` + agent loop, `Conversation` helper,
`PricingTable`, vision and document blocks, prompt-cache sugar, sync
feature
- **v0.3** Batches (with poller), Files API, citations, typed built-in
tool wrappers, context compaction
- **v0.4** Agent-loop guardrails (parallel dispatch + cost budget +
cancellation), streaming callbacks, `dry_run`, `cost_preview`,
`#[derive(Tool)]` proc macro, mid-stream tool approval gates,
record/replay test harness, Bedrock auth (sigv4 signer)
- **v0.5** Admin / Skills / User Profiles / Managed Agents preview
endpoints, typed `BetaHeader` enum, spec-diff tooling, live-test
cassettes
- **v0.6+** Vertex AI auth, Tower `Service` -> `Tool` integration,
typed promotions for `stop_details` / `context_management` /
`ModelCapabilities`, streaming-SSE cassette recording, vault
credential live tests
## Anti-goals
If a feature request comes in for any of these, the answer is "different
crate":
- Local prompt templating
- Multi-provider routing (OpenAI, Gemini, etc.)
- Response caching layer
- Background queues or scheduling
- Vector store integrations
- Embedding API (Anthropic does not have one; do not stub)
- Legacy `/v1/complete` Completions API
## MSRV
Rust 1.82 or later.
## License
Licensed under either of [Apache-2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT)
at your option. Contributions are dual-licensed under the same terms.