---
title: Claude
description: Use @codespar/claude to give Anthropic Claude agents commerce capabilities in Latin America.
---

import { Callout } from "fumadocs-ui/components/callout";
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
import { Steps, Step } from "fumadocs-ui/components/steps";

# Claude Adapter

<VersionBadge pkg="@codespar/claude" />

The `@codespar/claude` adapter converts CodeSpar session tools into Anthropic's tool format and handles tool-use blocks in the response loop. It works with the official `@anthropic-ai/sdk` and provides four exported functions: `getTools`, `toClaudeTool`, `handleToolUse`, and `toToolResultBlock`.

<Callout type="info">
**Pick this adapter when** you need the strongest tool-calling accuracy for multi-step commerce flows, long-context reasoning over order histories or audit trails, or you are already on the Anthropic API. It is the reference implementation for the CodeSpar Complete Loop.
</Callout>

## Framework-specific notes

- **Parallel tool calls** — Claude emits multiple `tool_use` blocks in one response when steps are independent. `handleToolUse` per block + `Promise.all` runs them concurrently. CodeSpar bills each settled transaction individually regardless.
- **`tool_use_id` round-trip** — each block has a unique `id`; `toToolResultBlock(block.id, result)` is mandatory or Claude rejects the next turn as malformed. The helper enforces this.
- **Long context = reconciliation friendly** — Claude Sonnet 4.6 handles 200K tokens, enough to stuff a full day's tool-call log into the conversation for audit-style agents without chunking.
- **System prompts matter for routing** — be explicit about which meta-tool to prefer for which intent. Claude's adherence to system prompts is the strongest of any adapter we ship.

## Installation

<Tabs items={["npm", "pnpm", "yarn"]}>
<Tab value="npm">
```bash
npm install @codespar/sdk @codespar/claude @anthropic-ai/sdk
```
</Tab>
<Tab value="pnpm">
```bash
pnpm add @codespar/sdk @codespar/claude @anthropic-ai/sdk
```
</Tab>
<Tab value="yarn">
```bash
yarn add @codespar/sdk @codespar/claude @anthropic-ai/sdk
```
</Tab>
</Tabs>

<Callout type="info">
`@codespar/claude` has peer dependencies on `@codespar/sdk@^0.10.0` and `@anthropic-ai/sdk@^0.30.0`. Make sure both are installed.
</Callout>
## API Reference

### `getTools(session): Promise<Anthropic.Tool[]>`

Fetches all tools from the session and converts them to Anthropic's `Tool[]` format. Each tool includes a `name`, `description`, and `input_schema` (JSON Schema). This is the primary function you will use -- it handles both fetching and formatting in a single call.

```typescript
import { CodeSpar } from "@codespar/sdk";
import { getTools } from "@codespar/claude";

const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });
const session = await codespar.create("user_123", {
  servers: ["stripe", "mercadopago"],
});

const tools = await getTools(session);
console.log(JSON.stringify(tools[0], null, 2));
```

```json title="Output: Anthropic.Tool"
{
  "name": "codespar_charge",
  "description": "Create an inbound charge (buyer pays merchant) — Pix / boleto / card",
  "input_schema": {
    "type": "object",
    "properties": {
      "provider": {
        "type": "string",
        "description": "Payment provider to use (e.g., stripe, mercadopago)"
      },
      "amount": {
        "type": "number",
        "description": "Amount in cents (e.g., 4990 for R$49.90)"
      },
      "currency": {
        "type": "string",
        "description": "ISO 4217 currency code (e.g., BRL)"
      },
      "description": {
        "type": "string",
        "description": "Product or service description"
      },
      "payment_methods": {
        "type": "array",
        "items": { "type": "string" },
        "description": "Accepted payment methods (pix, card, boleto)"
      }
    },
    "required": ["provider", "amount", "currency"]
  }
}
```

<Callout type="warn">
`getTools` is async because it calls `session.tools()` under the hood. Always `await` it. Forgetting to await will pass a Promise instead of an array to `anthropic.messages.create`, causing a runtime error.
</Callout>
### `toClaudeTool(tool): Anthropic.Tool`

Converts a single CodeSpar tool definition to Anthropic's `Tool` format. Use this when you have already fetched tools via `session.tools()` and want to convert them individually -- for example, to filter or transform tools before passing them to Claude.

```typescript
import { toClaudeTool } from "@codespar/claude";

const allTools = await session.tools();

// Filter to only payment-related tools
const paymentTools = allTools
  .filter((t) => ["codespar_charge", "codespar_pay"].includes(t.name))
  .map(toClaudeTool);

// Use the filtered set with Claude
const response = await anthropic.messages.create({
  model: "claude-sonnet-4-20250514",
  max_tokens: 4096,
  tools: paymentTools,
  messages,
});
```

The function maps the CodeSpar tool schema to Anthropic's expected format:

```typescript
// Input: CodeSpar Tool
{ name: string; description: string; input_schema: JSONSchema }

// Output: Anthropic.Tool
{ name: string; description: string; input_schema: JSONSchema }
```

### `handleToolUse(session, toolUseBlock): Promise<unknown>`

Executes a tool-use block from Claude's response against the CodeSpar session. It extracts the tool `name` and `input` from the block, calls `session.execute()`, and returns the raw result.

```typescript
import { handleToolUse } from "@codespar/claude";

// toolUseBlock comes from Claude's response content
// { type: "tool_use", id: "toolu_abc123", name: "codespar_charge", input: {...} }

const result = await handleToolUse(session, toolUseBlock);
console.log(JSON.stringify(result, null, 2));
```

```json title="Return value"
{
  "charge_id": "pay_7f8g9h0i1j2k",
  "qr_code": "00020126360014BR.GOV.BCB.PIX0114...",
  "qr_code_image_url": "https://cdn.asaas.com/qr/...",
  "amount": 4990,
  "currency": "BRL",
  "status": "pending",
  "expires_at": "2026-04-16T14:30:00Z"
}
```

<Callout type="info">
The return type is `unknown` because each tool returns a different shape. You can cast it to a specific type if you know which tool was called, but typically you pass the result directly to `toToolResultBlock` without inspecting it.
</Callout>
### `toToolResultBlock(toolUseId, result): Anthropic.ToolResultBlockParam`

Wraps a tool result into Anthropic's `ToolResultBlockParam` format so it can be sent back to Claude in the next message. It JSON-stringifies the result and sets the correct `tool_use_id`.

```typescript
import { toToolResultBlock } from "@codespar/claude";

const block = toToolResultBlock(toolUseBlock.id, result);
console.log(JSON.stringify(block, null, 2));
```

```json title="Output: Anthropic.ToolResultBlockParam"
{
  "type": "tool_result",
  "tool_use_id": "toolu_abc123",
  "content": "{\"charge_id\":\"pay_7f8g9h0i1j2k\",\"qr_code\":\"00020126360014BR.GOV.BCB.PIX0114...\",\"amount\":4990,\"currency\":\"BRL\",\"status\":\"pending\",\"expires_at\":\"2026-04-16T14:30:00Z\"}"
}
```

For error cases, pass an error object as the result:

```typescript
const errorBlock = toToolResultBlock(toolUseBlock.id, {
  error: "Payment provider returned: insufficient funds",
});
// Claude will see the error and can retry or ask the user for clarification
```

## Full agent loop

This is a complete, production-ready example of a Claude agent that processes commerce operations. It includes error handling, multi-turn conversation, and session cleanup.

```typescript title="claude-agent.ts"
import Anthropic from "@anthropic-ai/sdk";
import { CodeSpar } from "@codespar/sdk";
import {
  getTools,
  handleToolUse,
  toToolResultBlock,
} from "@codespar/claude";

const anthropic = new Anthropic();
const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });

async function run(userMessage: string) {
  // 1. Create a session with the servers you need
  const session = await codespar.create("user_123", {
    servers: ["stripe", "mercadopago", "correios"],
  });

  // 2. Get tools in Anthropic format
  const tools = await getTools(session);

  // 3. Start the conversation
  const messages: Anthropic.MessageParam[] = [
    { role: "user", content: userMessage },
  ];

  let response = await anthropic.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 4096,
    system:
      "You are a commerce assistant for a Brazilian e-commerce store. " +
      "Use the available tools to help the user with payments, invoicing, " +
      "and shipping. Always confirm amounts and details before processing. " +
      "Respond in the same language the user writes in.",
    tools,
    messages,
  });

  // 4. Tool-use loop
  while (response.stop_reason === "tool_use") {
    const toolUseBlocks = response.content.filter(
      (b) => b.type === "tool_use"
    );

    const toolResults = await Promise.all(
      toolUseBlocks.map(async (block) => {
        try {
          const result = await handleToolUse(session, block);
          return toToolResultBlock(block.id, result);
        } catch (error) {
          return toToolResultBlock(block.id, {
            error: error instanceof Error ? error.message : "Tool call failed",
          });
        }
      })
    );

    messages.push({ role: "assistant", content: response.content });
    messages.push({ role: "user", content: toolResults });

    response = await anthropic.messages.create({
      model: "claude-sonnet-4-20250514",
      max_tokens: 4096,
      tools,
      messages,
    });
  }

  // 5. Close the session when done
  await session.close();

  // 6. Return the final text
  const text = response.content.find((b) => b.type === "text");
  return text?.type === "text" ? text.text : "";
}

// Usage
const reply = await run("Create a R$99 Pix payment for order #1234");
console.log(reply);
```

## Handling parallel tool calls

Claude may return multiple `tool_use` blocks in a single response when it needs to execute operations in parallel. The adapter handles this naturally -- map over all blocks and return all results:

```typescript
const toolUseBlocks = response.content.filter((b) => b.type === "tool_use");

// Execute all tool calls in parallel
const toolResults = await Promise.all(
  toolUseBlocks.map(async (block) => {
    const result = await handleToolUse(session, block);
    return toToolResultBlock(block.id, result);
  })
);

// Send all results back in a single message
messages.push({ role: "assistant", content: response.content });
messages.push({ role: "user", content: toolResults });
```

<Callout type="info">
Parallel tool calls are common when Claude chains operations. For example, after creating a checkout link, Claude might simultaneously call `codespar_notify` to send it via WhatsApp and `codespar_invoice` to prepare the fiscal document.
</Callout>
## Streaming

For real-time output, use `anthropic.messages.stream()` instead of `create()`. The tool-use loop works the same way -- you just need to handle the streamed final message differently:

```typescript title="claude-streaming.ts"
import Anthropic from "@anthropic-ai/sdk";
import { CodeSpar } from "@codespar/sdk";
import { getTools, handleToolUse, toToolResultBlock } from "@codespar/claude";

const anthropic = new Anthropic();
const codespar = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });

async function runStreaming(userMessage: string) {
  const session = await codespar.create("user_123", {
    servers: ["stripe", "mercadopago"],
  });

  const tools = await getTools(session);
  const messages: Anthropic.MessageParam[] = [
    { role: "user", content: userMessage },
  ];

  let continueLoop = true;

  while (continueLoop) {
    const stream = anthropic.messages.stream({
      model: "claude-sonnet-4-20250514",
      max_tokens: 4096,
      tools,
      messages,
    });

    // Stream text chunks to the console
    stream.on("text", (text) => process.stdout.write(text));

    const response = await stream.finalMessage();

    if (response.stop_reason === "tool_use") {
      const toolUseBlocks = response.content.filter(
        (b) => b.type === "tool_use"
      );

      const toolResults = await Promise.all(
        toolUseBlocks.map(async (block) => {
          try {
            const result = await handleToolUse(session, block);
            return toToolResultBlock(block.id, result);
          } catch (error) {
            return toToolResultBlock(block.id, {
              error: error instanceof Error ? error.message : "Tool call failed",
            });
          }
        })
      );

      messages.push({ role: "assistant", content: response.content });
      messages.push({ role: "user", content: toolResults });
    } else {
      continueLoop = false;
    }
  }

  await session.close();
}

await runStreaming("Create a R$49.90 Pix charge for the Pro Plan");
```

## Error handling

There are three categories of errors to handle:

### 1. Session errors

These occur when creating or using a session:

```typescript
try {
  const session = await codespar.create("user_123", {
    servers: ["stripe"],
  });
} catch (error) {
  if (error instanceof Error) {
    // INVALID_API_KEY, RATE_LIMITED, SERVER_NOT_FOUND
    console.error("Session error:", error.message);
  }
}
```

### 2. Tool execution errors

These occur when a tool call fails (e.g., invalid parameters, provider error). The best practice is to return the error as a tool result so Claude can reason about it:

```typescript
const toolResults = await Promise.all(
  toolUseBlocks.map(async (block) => {
    try {
      const result = await handleToolUse(session, block);
      return toToolResultBlock(block.id, result);
    } catch (error) {
      // Return the error to Claude instead of throwing
      return toToolResultBlock(block.id, {
        error: error instanceof Error ? error.message : "Tool call failed",
        tool_name: block.name,
        input: block.input,
      });
    }
  })
);
```

<Callout type="info">
Returning errors as tool results (instead of throwing) lets Claude reason about the failure. Claude may retry with different parameters, ask the user for clarification, or suggest an alternative approach.
</Callout>
### 3. Anthropic API errors

These are standard SDK errors (rate limits, context length, etc.):

```typescript
try {
  response = await anthropic.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 4096,
    tools,
    messages,
  });
} catch (error) {
  if (error instanceof Anthropic.RateLimitError) {
    // Implement exponential backoff
  } else if (error instanceof Anthropic.APIError) {
    console.error(`Anthropic API error: ${error.status} ${error.message}`);
  }
}
```

## Best practices

1. **Always close sessions.** Use `try/finally` to ensure `session.close()` runs even if the agent loop throws.

2. **Scope servers narrowly.** Only connect the servers your agent actually needs. `["stripe"]` is better than `["stripe", "mercadopago", "asaas", "pagarme"]` if you only use Stripe.

3. **Set a system prompt.** Tell Claude what domain it operates in and what tools to prefer. This reduces unnecessary `codespar_discover` calls.

4. **Return errors as tool results.** Never let `handleToolUse` exceptions bubble up and crash the loop. Return them as structured tool results so Claude can self-correct.

5. **Limit loop iterations.** Add a maximum iteration count to prevent infinite loops if Claude keeps calling tools:

```typescript
const MAX_ITERATIONS = 10;
let iterations = 0;

while (response.stop_reason === "tool_use" && iterations < MAX_ITERATIONS) {
  // ... tool-use handling ...
  iterations++;
}

if (iterations >= MAX_ITERATIONS) {
  console.warn("Agent reached maximum tool-call iterations");
}
```

## Newer SDK wrappers

The adapter wires the model to `session.tools()` + `session.execute()`. For higher-level flows you can call typed wrappers on the session directly from inside (or alongside) the agent loop — they hit the same routing infrastructure but skip the LLM hop:

- `session.discover(query)` — search the catalog (powers `codespar_discover` programmatically).
- `session.charge(args)` / `session.pay(args)` / `session.ship(args)` — typed shortcuts for the most common meta-tools.
- `session.connectionWizard(serverId)` — open a hosted auth flow for a missing connection.
- `session.paymentStatus(toolCallId)` and `session.paymentStatusStream(toolCallId)` — async settlement correlation (poll or SSE).
- `session.verificationStatus(toolCallId)` and `session.verificationStatusStream(toolCallId)` — KYC outcome polling / SSE.

Full reference at [/docs/api/sdk](/docs/api/sdk).

## Next steps

<NextStepsGrid items={[
  { label: "CONCEPT", title: "Sessions", description: "Session lifecycle, server selection, and scoping.", href: "/docs/concepts/sessions" },
  { label: "CONCEPT", title: "Tools & Meta-Tools", description: "What tools are available and how routing works.", href: "/docs/concepts/tools" },
  { label: "PROVIDER", title: "OpenAI Adapter", description: "If you are using GPT models instead.", href: "/docs/providers/openai" },
  { label: "PROVIDER", title: "Vercel AI SDK", description: "Streaming-first agents for Next.js.", href: "/docs/providers/vercel" },
  { label: "QUICKSTART", title: "Quickstart", description: "End-to-end setup in under 5 minutes.", href: "/docs/quickstart" },
]} />
