Skip to main content
code<spar>

Quickstart

Get your first AI agent commerce interaction running in under 5 minutes.

Quickstart

This guide walks you through installing the SDK, creating a session, executing a tool call, and wiring it into a full agent loop -- all in under 5 minutes. By the end, you will have a working commerce agent that can process payments in Brazil.

Prerequisites

  • Node.js 18+ installed
  • A CodeSpar API key (get one at codespar.dev/dashboard/settings)
  • An LLM provider account (Anthropic, OpenAI, or any Vercel AI SDK provider)

Install the SDK and an adapter

Install the core SDK and the adapter for your preferred framework:

npm install @codespar/sdk @codespar/claude @anthropic-ai/sdk
npm install @codespar/sdk @codespar/openai openai
npm install @codespar/sdk @codespar/vercel ai @ai-sdk/anthropic

[!TIP] Using pnpm or yarn? Replace npm install with pnpm add or yarn add. All packages are published on the public npm registry.

Set your API keys

You need two environment variables -- one for CodeSpar, one for your LLM provider:

export CODESPAR_API_KEY="csk_live_your_key_here"
export ANTHROPIC_API_KEY="sk-ant-your_key_here"
export CODESPAR_API_KEY="csk_live_your_key_here"
export OPENAI_API_KEY="sk-your_key_here"
export CODESPAR_API_KEY="csk_live_your_key_here"
export ANTHROPIC_API_KEY="sk-ant-your_key_here"

[!NOTE] API keys prefixed with csk_test_ route to sandbox servers with mock data. Use csk_live_ for production. Both share the same API surface, so you can develop against sandbox and switch to production by changing one variable.

Create a session

A session is a scoped connection to one or more MCP servers. It manages authentication, tool routing, and usage tracking. Think of it as a database connection pool -- you create one, use it for the duration of your interaction, and close it when done.

index.ts
import { CodeSpar } from "@codespar/sdk";

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

const session = await codespar.sessions.create({
  servers: ["stripe", "mercadopago"],
});

console.log("Session ID:", session.id);
console.log("Status:", session.status);
console.log("Servers:", session.servers);
Output
{
  "id": "ses_a1b2c3d4e5f6",
  "status": "active",
  "servers": ["stripe", "mercadopago"],
  "created_at": "2026-04-15T14:30:00Z",
  "expires_at": "2026-04-15T15:30:00Z"
}

[!WARNING] Sessions expire after 1 hour of inactivity. For long-running agents, implement session renewal or create a new session per interaction. See Sessions for lifecycle details.

List available tools

Once your session is active, retrieve the tools available from the connected servers. The session.tools() method is async and returns an array of tool definitions:

index.ts
const tools = await session.tools();

console.log(`${tools.length} tools available:`);
tools.forEach((t) => {
  console.log(`  - ${t.name}: ${t.description}`);
});
Output
[
  {
    "name": "codespar_discover",
    "description": "Find available commerce tools by domain",
    "input_schema": {
      "type": "object",
      "properties": {
        "domain": {
          "type": "string",
          "enum": ["payments", "fiscal", "logistics", "messaging", "banking", "erp", "crypto"]
        }
      },
      "required": ["domain"]
    }
  },
  {
    "name": "codespar_checkout",
    "description": "Create a checkout session for a product or service",
    "input_schema": { "..." : "..." }
  },
  {
    "name": "codespar_pay",
    "description": "Process a payment via Pix, boleto, or card",
    "input_schema": { "..." : "..." }
  }
]

[!NOTE] The tools returned depend on which servers you connected in the session. Connecting ["stripe", "mercadopago"] gives you payment tools. Add "correios" to also get shipping tools.

Execute a tool call

Call a tool directly against the session to verify everything is wired correctly:

index.ts
const result = await session.execute({
  name: "codespar_discover",
  arguments: { domain: "payments" },
});

console.log(JSON.stringify(result, null, 2));
Response
{
  "domain": "payments",
  "servers": ["stripe", "mercadopago"],
  "tools": [
    {
      "name": "codespar_checkout",
      "description": "Create a checkout session for a product or service"
    },
    {
      "name": "codespar_pay",
      "description": "Process a payment via Pix, boleto, or card"
    }
  ],
  "capabilities": ["pix", "boleto", "credit_card", "checkout_link", "recurring"]
}

Now try creating a checkout link:

index.ts
const checkout = await session.execute({
  name: "codespar_checkout",
  arguments: {
    provider: "stripe",
    amount: 4990,
    currency: "BRL",
    description: "Pro Plan - Monthly",
    payment_methods: ["pix", "card"],
  },
});

console.log(JSON.stringify(checkout, null, 2));
Response
{
  "checkout_id": "chk_7f8g9h0i1j2k",
  "url": "https://checkout.stripe.com/c/pay/cs_live_a1b2c3...",
  "amount": 4990,
  "currency": "BRL",
  "description": "Pro Plan - Monthly",
  "payment_methods": ["pix", "card"],
  "status": "open",
  "expires_at": "2026-04-16T14:30:00Z"
}

Wire it into an agent

Now connect everything to a real LLM. Choose your framework:

agent-claude.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 session with the servers you need
  const session = await codespar.sessions.create({
    servers: ["stripe", "mercadopago"],
  });

  // 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 with payments, invoicing, and shipping. " +
      "Always confirm amounts and details before processing payments.",
    tools,
    messages,
  });

  // 4. Tool-use loop: keep going until Claude stops calling tools
  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. Clean up
  await session.close();

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

// Run it
const reply = await run("Create a R$49.90 checkout link for 'Pro Plan' using Stripe");
console.log(reply);

See the full Claude adapter guide for streaming, error handling, and advanced patterns.

agent-openai.ts
import OpenAI from "openai";
import { CodeSpar } from "@codespar/sdk";
import { getTools, handleToolCall } from "@codespar/openai";

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

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

  const tools = await getTools(session);

  const messages: OpenAI.ChatCompletionMessageParam[] = [
    {
      role: "system",
      content:
        "You are a commerce assistant for a Brazilian store. " +
        "Use the available tools for payments, invoicing, and shipping.",
    },
    { role: "user", content: userMessage },
  ];

  let response = await openai.chat.completions.create({
    model: "gpt-4o",
    tools,
    messages,
  });

  let message = response.choices[0].message;

  while (message.tool_calls && message.tool_calls.length > 0) {
    messages.push(message);

    for (const toolCall of message.tool_calls) {
      let content: string;
      try {
        content = await handleToolCall(session, toolCall);
      } catch (error) {
        content = JSON.stringify({
          error: error instanceof Error ? error.message : "Tool call failed",
        });
      }
      messages.push({
        role: "tool",
        tool_call_id: toolCall.id,
        content,
      });
    }

    response = await openai.chat.completions.create({
      model: "gpt-4o",
      tools,
      messages,
    });
    message = response.choices[0].message;
  }

  await session.close();
  return message.content ?? "";
}

const reply = await run("Generate a Pix QR code for R$250");
console.log(reply);

See the full OpenAI adapter guide for streaming and advanced patterns.

agent-vercel.ts
import { generateText } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { CodeSpar } from "@codespar/sdk";
import { getTools } from "@codespar/vercel";

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

const session = await codespar.sessions.create({
  servers: ["stripe", "mercadopago"],
});

const tools = await getTools(session);

const { text } = await generateText({
  model: anthropic("claude-sonnet-4-20250514"),
  tools,
  maxSteps: 5,
  system:
    "You are a commerce assistant for a Brazilian e-commerce store. " +
    "Use the available tools for payments, invoicing, and shipping.",
  prompt: "Create a R$49.90 checkout link for 'Pro Plan' via Stripe",
});

console.log(text);
await session.close();

See the full Vercel AI SDK guide for streamText, Next.js API routes, and the useChat hook.

The Complete Loop in action

Here is what happens when you run the Claude example above. The agent performs the Complete Loop automatically:

  1. Claude receives the prompt and sees the available tools from getTools.
  2. Claude calls codespar_discover (optional) to understand available payment providers.
  3. Claude calls codespar_checkout with the amount, currency, and provider.
  4. CodeSpar routes the request to the Stripe MCP server, which creates a real checkout session.
  5. Claude receives the result (checkout URL, status, expiry) and formats a response for the user.
User: "Create a R$49.90 checkout link for 'Pro Plan' using Stripe"

Claude thinks: I need to create a checkout link. I have the codespar_checkout tool.

Claude calls: codespar_checkout({
  provider: "stripe",
  amount: 4990,
  currency: "BRL",
  description: "Pro Plan",
  payment_methods: ["pix", "card"]
})

CodeSpar returns: {
  checkout_id: "chk_7f8g9h0i1j2k",
  url: "https://checkout.stripe.com/c/pay/cs_live_...",
  status: "open"
}

Claude responds: "I've created your checkout link for the Pro Plan at R$49.90.
Here it is: https://checkout.stripe.com/c/pay/cs_live_...
The link accepts both Pix and card payments and expires in 24 hours."

Try the sandbox

Don't want to set up locally? Try the interactive sandbox at codespar.dev/dashboard/sandbox. It provides a live chat interface where you can test tool calls with mock servers -- no API key required.

[!TIP] The sandbox uses csk_test_ keys internally. All tool calls return realistic mock data. It is a great way to explore the 6 meta-tools before writing any code.

Common errors

ErrorCauseFix
INVALID_API_KEYMissing or malformed API keyCheck that CODESPAR_API_KEY is set and starts with csk_live_ or csk_test_
SESSION_EXPIREDSession timed out after 1 hour of inactivityCreate a new session
SERVER_NOT_FOUNDRequested a server that does not existCheck available servers with codespar_discover
TOOL_NOT_FOUNDCalled a tool not available in the current sessionVerify the tool exists with session.tools()
RATE_LIMITEDToo many requests in a short periodImplement exponential backoff or reduce request frequency

Next steps