Skip to main content

Sessions

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

1 min read · updated

Sessions

@codespar/sdkv0.9.0

A session is the core runtime primitive in CodeSpar. It represents a scoped, authenticated connection to one or more MCP 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, scoped to your API key, and auditable through the dashboard.

Tenancy. Sessions are scoped to a user (userId) inside a project inside your organization. Pass x-codespar-project: prj_<16chars> on HTTP requests to target a specific project, or omit the header to fall back to your org's default project. Examples below use defaults -- see the Projects concept for when to scope explicitly.

Session lifecycle

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.

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.

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, not for tool calls or session duration.

Creating a session

With explicit servers

import {  } from "@codespar/sdk";

const  = new ({ : .. });

const session = await .("user_123", {
const session: Session
: ["stripe", "mercadopago", "correios"], }); .(.); // "ses_abc123def456" .(.); // "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

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:

{
  "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

ParameterTypeRequiredDefaultDescription
userId (1st arg)stringYes--End-user identifier on behalf of whom the agent acts
serversstring[]Yes*--List of MCP server identifiers to connect
presetstringNo--A named preset that bundles multiple servers
manageConnectionsobjectNo--Controls whether to wait for servers to finish connecting
projectIdstringNoorg defaultTarget a specific project (prj_<16chars>)
metadataRecord<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.

// 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

PresetUse case
brazilianFull Brazilian commerce stack (payments, fiscal, logistics, messaging, banking, ERP)
mexicanMexican commerce stack (Conekta, Facturapi, Skydropx, STP/SPEI, Bind ERP)
argentinianArgentine commerce stack (payments, AFIP, Andreani, BCRA, Colppy)
colombianColombian commerce stack (Wompi, Siigo, Coordinadora, Nequi, Alegra)
allEvery server in the catalog

Presets can be combined with explicit servers. The servers array is merged with the preset's server list and duplicates are removed automatically.

// 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.

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.

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.

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);
  }
}

execute, send, and sendStream all route through the CodeSpar API for audit and billing. Only settled transactions count toward your bill -- read-only tool calls (quotes, lookups, discovery) are free.

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.

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.

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:

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:

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

session.tools() is async -- it fetches the current tool list from the connected servers. Always await it. The response includes both meta-tools and server-specific tools.

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.

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"}`);
}
curl https://api.codespar.dev/v1/sessions/ses_abc123/connections \
  -H "Authorization: Bearer csk_live_..."

Response:

{
  "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

StateDescriptionTransitions to
pendingSession is being created; servers are connectingactive, error
activeSession is open and ready for tool callsclosed
closedSession has been closed (manually or by 30-min timeout)Terminal
errorSession creation failed (check server availability)Terminal

Closing a session

try {
  // use session...
} finally {
  await session.close();
}
curl -X DELETE https://api.codespar.dev/v1/sessions/ses_abc123 \
  -H "Authorization: Bearer csk_live_..."

Sessions not explicitly closed are automatically terminated after 30 minutes of inactivity. You are billed only for settled transactions, not for tool calls or session duration.

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

Edit on GitHub

Last updated on