---
title: Sessions
description: Sessions are scoped connections to MCP servers that manage tool access, authentication, and usage tracking for AI agent commerce operations.
---

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

# Sessions

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

A **session** is the core runtime primitive in CodeSpar. It represents a scoped, authenticated connection to one or more [MCP servers](/docs/api/servers), giving your AI agent access to commerce tools across payments, fiscal, logistics, and messaging providers in Latin America.

Sessions solve a fundamental problem: an AI agent needs to interact with dozens of commerce APIs, each with its own authentication, data format, and rate limits. Instead of wiring each provider individually, you create a session, specify which servers you need, and CodeSpar handles the rest.

Every tool call made through a session is metered for [billing](/docs/concepts/billing), scoped to your [API key](/docs/concepts/authentication), and auditable through the dashboard.

<Callout type="info">
**Tenancy.** Sessions are scoped to a user (`userId`) inside a [project](/docs/concepts/projects) inside your account. Pass `x-codespar-project: prj_<16chars>` on HTTP requests to target a specific project, or omit the header to fall back to your account's default project. Examples below use defaults -- see the [Projects concept](/docs/concepts/projects) for when to scope explicitly.
</Callout>

## Session lifecycle

<Steps>
<Step>
**Create** -- Call `codespar.create(userId, config)` to open a session. CodeSpar authenticates with each requested server using your stored credentials and returns a session ready to accept tool calls. This typically completes in 200-400ms.
</Step>
<Step>
**Use** -- Drive the session with one of three patterns: (1) direct tool calls via `session.execute(toolName, params)`, (2) natural-language messages via `session.send(message)` for a full agent loop, or (3) streaming with `session.sendStream(message)`. All operations are scoped to the session's connected servers.
</Step>
<Step>
**Close** -- When the conversation or workflow is done, call `session.close()` to release resources. Open sessions are automatically closed after 30 minutes of inactivity. You are only billed for [settled transactions](/docs/concepts/billing), not for tool calls or session duration.
</Step>
</Steps>

## Creating a session

### With explicit servers

```ts twoslash
import { CodeSpar } from "@codespar/sdk";

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

const session = await codespar.create("user_123", {
//    ^?
  servers: ["stripe", "mercadopago", "correios"],
});

console.log(session.id);     // "ses_abc123def456"
console.log(session.status); // "active"
```

The first argument is your end-user identifier -- whatever string uniquely identifies the user on behalf of whom the agent is acting. It lets CodeSpar scope credentials, audit logs, and billing to the right user.

### With curl

```bash
curl -X POST https://api.codespar.dev/v1/sessions \
  -H "Authorization: Bearer csk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "user_123",
    "servers": ["stripe", "mercadopago", "correios"]
  }'
```

**Response:**

```json
{
  "id": "ses_abc123def456",
  "user_id": "user_123",
  "status": "active",
  "servers": [
    { "id": "stripe", "name": "Stripe", "status": "connected" },
    { "id": "mercadopago", "name": "Mercado Pago", "status": "connected" },
    { "id": "correios", "name": "Correios", "status": "connected" }
  ],
  "created_at": "2026-04-15T10:30:00Z",
  "expires_at": "2026-04-15T11:00:00Z"
}
```

### Session options

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `userId` (1st arg) | `string` | Yes | -- | End-user identifier on behalf of whom the agent acts |
| `servers` | `string[]` | Yes* | -- | List of MCP server identifiers to connect |
| `preset` | `string` | No | -- | A named preset that bundles multiple servers |
| `manageConnections` | `object` | No | -- | Controls whether to wait for servers to finish connecting |
| `projectId` | `string` | No | account default | Target a specific project (`prj_<16chars>`) |
| `metadata` | `Record<string,string>` | No | -- | Key-value metadata attached to every tool call |

*Required unless `preset` is specified.

## Presets

Presets are named bundles of servers optimized for common commerce workflows. They reduce boilerplate and ensure you include all the servers a workflow typically needs.

```typescript
// These are equivalent:
const session = await codespar.create("user_123", {
  servers: ["stripe", "mercadopago", "asaas", "pagarme"],
});

const session = await codespar.create("user_123", {
  preset: "brazilian",
});
```

### Country presets

| Preset | Use case |
|--------|----------|
| `brazilian` | Full Brazilian commerce stack (payments, fiscal, logistics, messaging, banking, ERP) |
| `mexican` | Mexican commerce stack (Conekta, Facturapi, Skydropx, STP/SPEI, Bind ERP) |
| `argentinian` | Argentine commerce stack (payments, AFIP, Andreani, BCRA, Colppy) |
| `colombian` | Colombian commerce stack (Wompi, Siigo, Coordinadora, Nequi, Alegra) |
| `all` | Every server in the catalog |

<Callout type="info">
Presets can be combined with explicit servers. The `servers` array is merged with the preset's server list and duplicates are removed automatically.
</Callout>

```typescript
// Brazilian preset + an extra crypto server
const session = await codespar.create("user_123", {
  preset: "brazilian",
  servers: ["mercado-bitcoin"],
});
```

## Executing tools

Sessions expose three execution patterns. Pick the one that matches how your agent drives the session.

### `session.execute(toolName, params)` -- direct tool call

Invoke a single tool by name and wait for its result. Use this when your code (or your own agent loop) has already decided which tool to call.

```typescript
const result = await session.execute("codespar_pay", {
  method: "pix",
  amount: 9990,
  currency: "BRL",
  description: "Order #1234",
  customer_email: "maria@example.com",
});

console.log(result);
// {
//   "success": true,
//   "data": {
//     "payment_id": "pay_abc123",
//     "status": "pending",
//     "pix_code": "00020126580014br.gov.bcb.pix...",
//     "qr_code_url": "https://api.codespar.dev/qr/pay_abc123.png",
//     "expires_at": "2026-04-15T11:00:00Z"
//   },
//   "server": "stripe",
//   "tool": "codespar_pay",
//   "duration": 347
// }
```

### `session.send(message)` -- natural-language agent loop

Hand CodeSpar a message in natural language; it runs a Claude tool-use loop on the backend, calling whichever tools the agent decides it needs, and returns the final response plus every tool call along the way. Use this when you want the simplest possible integration -- no framework, no tool orchestration code.

```typescript
const result = await session.send(
  "Charge R$150 via Pix for order #5678 and send a WhatsApp confirmation to the customer",
);

console.log(result.message);     // Final agent response text
console.log(result.tool_calls);  // Every tool the agent called
console.log(result.iterations);  // How many model turns it took
```

### `session.sendStream(message)` -- streaming agent loop

Same as `send()` but yields events as they happen -- useful when you want to show progress to the user or stream the response through your UI.

```typescript
for await (const event of session.sendStream("Charge R$150 via Pix")) {
  if (event.type === "assistant_text") {
    process.stdout.write(event.content);
  }
  if (event.type === "tool_use") {
    console.log(`→ calling ${event.name}`);
  }
  if (event.type === "done") {
    console.log("\nDone:", event.result.message);
  }
}
```

<Callout type="info">
`execute`, `send`, and `sendStream` all route through the CodeSpar API for audit and billing. Only [settled transactions](/docs/concepts/billing) count toward your bill -- read-only tool calls (quotes, lookups, discovery) are free.
</Callout>

## Structured workflows with `session.loop()`

For deterministic multi-step workflows where you know the tool sequence in advance, `session.loop()` runs a list of steps in order with access to previous results. Unlike `send()`, there is no LLM in the middle -- you define the exact sequence.

```typescript
const result = await session.loop({
  steps: [
    {
      tool: "codespar_pay",
      params: { method: "pix", amount: 15000, currency: "BRL" },
    },
    {
      tool: "codespar_invoice",
      params: (prev) => ({ payment_id: prev[0].data.payment_id }),
    },
    {
      tool: "codespar_notify",
      params: (prev) => ({
        channel: "whatsapp",
        template: "order_confirmation",
        variables: { invoice_url: prev[1].data.pdf_url },
      }),
    },
  ],
  abortOnError: true,
});

console.log(result.success);         // true if all steps completed
console.log(result.completedSteps);  // 3
console.log(result.results);         // ToolResult[] for each step
```

## MCP integration via `session.mcp`

For IDE-based workflows (Claude Desktop, Cursor, Windsurf), every session exposes an MCP endpoint as a property. Any MCP-compatible client can connect to it and get access to all the session's tools.

```typescript
console.log(session.mcp);
// {
//   "url": "https://api.codespar.dev/mcp/ses_abc123def456",
//   "headers": { "Authorization": "Bearer csk_live_..." }
// }
```

Add the returned URL and headers to your MCP client configuration and all session tools become available directly in your IDE.

## Listing tools

Once a session is active, retrieve all available tools:

```typescript
const tools = await session.tools();

for (const tool of tools) {
  console.log(`${tool.name}: ${tool.description}`);
}
// codespar_discover: Find available commerce tools by domain
// codespar_checkout: Create a checkout session for a product or service
// codespar_pay: Process payments via Pix, boleto, card, or wallet
// ...plus server-specific tools from connected servers
```

Or search by intent:

```typescript
const matches = await session.findTools("process a Pix payment");
// Tools ranked by relevance to the query
```

<Callout type="warn">
`session.tools()` is **async** -- it fetches the current tool list from the connected servers. Always `await` it. The response includes both [meta-tools](/docs/concepts/tools) and server-specific tools.
</Callout>

## Managing connections

Some MCP servers require user-level authentication (e.g., connecting a merchant's own Stripe account via OAuth). Use `session.authorize()` to start an OAuth flow and `session.connections()` to inspect status.

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

const auth = await session.authorize("mercadopago");
if (!auth.connected && auth.redirectUrl) {
  // Redirect user to OAuth consent screen
  console.log(`Connect Mercado Pago: ${auth.redirectUrl}`);
}

const connections = await session.connections();
for (const conn of connections) {
  console.log(`${conn.id}: ${conn.connected ? "connected" : "pending"}`);
}
```

```bash
curl https://api.codespar.dev/v1/sessions/ses_abc123/connections \
  -H "Authorization: Bearer csk_live_..."
```

**Response:**

```json
{
  "connections": [
    {
      "id": "stripe",
      "name": "Stripe",
      "connected": true,
      "connected_at": "2026-04-15T10:31:00Z"
    },
    {
      "id": "mercadopago",
      "name": "Mercado Pago",
      "connected": false,
      "redirectUrl": "https://codespar.dev/connect/mercadopago?session=ses_abc123"
    }
  ]
}
```

The user visits the `redirectUrl`, authenticates with the provider, and the connection status transitions to `connected: true`. Subsequent tool calls to that server will use the user's own credentials.

## Session states

| State | Description | Transitions to |
|-------|-------------|----------------|
| `pending` | Session is being created; servers are connecting | `active`, `error` |
| `active` | Session is open and ready for tool calls | `closed` |
| `closed` | Session has been closed (manually or by 30-min timeout) | Terminal |
| `error` | Session creation failed (check server availability) | Terminal |

## Closing a session

```typescript
try {
  // use session...
} finally {
  await session.close();
}
```

```bash
curl -X DELETE https://api.codespar.dev/v1/sessions/ses_abc123 \
  -H "Authorization: Bearer csk_live_..."
```

<Callout type="info">
Sessions not explicitly closed are automatically terminated after **30 minutes** of inactivity. You are billed only for [settled transactions](/docs/concepts/billing), not for tool calls or session duration.
</Callout>

## Best practices

1. **Scope sessions narrowly.** Only connect the servers you need. Fewer servers means faster session creation, a smaller tool list for the LLM to parse, and lower token costs in the context window.
2. **Close sessions when done.** Especially in serverless environments (Vercel, AWS Lambda) where the process may be recycled before the 30-minute timeout. Prefer `try { ... } finally { await session.close(); }`.
3. **Reuse sessions across turns.** In a multi-turn conversation, create the session once and reuse it for all turns. Do not create a new session per message.
4. **Pick the right primitive.** Use `execute()` when your code decides the tool, `send()` for the simplest agent loop, `sendStream()` for UI streaming, and `loop()` for deterministic multi-step workflows.
5. **Use presets for common patterns.** They reduce boilerplate and are maintained by CodeSpar as new servers are added to a category.
6. **Handle connection errors gracefully.** If a server fails to connect, the session still becomes `active` with the remaining servers. Check `session.connections()` to verify which connections succeeded.

## Next steps

<NextStepsGrid items={[
  { label: "CONCEPT", title: "Tools & Meta-Tools", description: "What tools are available in a session and how routing works.", href: "/docs/concepts/tools" },
  { label: "CONCEPT", title: "Authentication", description: "API keys, scopes, and provider credential management.", href: "/docs/concepts/authentication" },
  { label: "REFERENCE", title: "SDK Reference", description: "Full TypeScript reference for every session method.", href: "/docs/api/sdk" },
  { label: "REFERENCE", title: "Sessions API", description: "HTTP endpoints for create, list, close, execute, send.", href: "/docs/api/sessions" },
  { label: "CONCEPT", title: "Billing", description: "Per-settled-transaction pricing — what's metered, what's free.", href: "/docs/concepts/billing" },
  { label: "COOKBOOK", title: "E-Commerce Checkout", description: "session.loop() for a deterministic checkout → invoice → ship pipeline.", href: "/docs/cookbooks/ecommerce-checkout" },
  { label: "COOKBOOK", title: "Streaming Chat Agent", description: "session.sendStream() backing a Next.js useChat UI.", href: "/docs/cookbooks/streaming-chat" },
  { label: "COOKBOOK", title: "Multi-Tenant Agent", description: "One userId per tenant + metadata.tenant_id for per-tenant billing.", href: "/docs/cookbooks/multi-tenant" },
]} />

