Skip to main content

CodeSpar client

new CodeSpar(config), create(), SessionConfig, SessionConfigSchema and the cs.api property.

4 min read
View MarkdownEdit on GitHub

The entry point. One CodeSpar per API key; it creates sessions and, from 0.12.0, carries the generated REST client on cs.api.

CodeSpar

Readnew CodeSpar(config?: CodeSparConfig)
PythonCodeSpar(api_key=..., base_url=..., project_id=..., timeout=...)

Constructs a client. Nothing is sent: the constructor validates the configuration and fails fast, so a misconfigured key or timeout surfaces here and not on the first call.

FieldTypeRequiredDefaultDescription
apiKeystringyes, here or in CODESPAR_API_KEYenv CODESPAR_API_KEYMust start with csk_ (csk_test_ picks the sandbox project, csk_live_ the live one)
baseUrlstringnoenv CODESPAR_BASE_URL, then https://api.codespar.devPoint it at a self-hosted runtime without changing call sites
projectIdstringnothe organization's default projectMust match ^prj_[A-Za-z0-9]{16}$; sent as x-codespar-project on every request
timeoutnumberno60000Default per-request timeout in milliseconds; every method also takes a trailing opts?: CallOptions ({ timeout, signal }) that overrides it per call
Example
import {  } from "@codespar/sdk";

const  = new ({
  : "csk_test_0000",
  : "prj_0000000000000000",
});
CodeSparConfig
interface CodeSparConfig {
  apiKey?: string;
  baseUrl?: string;
  projectId?: string;
  /** Default per-request timeout in ms. Default 60000. */
  timeout?: number;
}

Throws a plain Error when no API key is found, when the key does not start with csk_, when projectId does not match the project id format, or when timeout is not a positive finite number.

Related Authentication, Projects.

create

Writecreate(userId: string, config?: SessionConfig): Promise<Session>
Pythoncs.create(user_id, config=None, /, **kwargs)

Opens a session scoped to a user. Sends POST /v1/sessions with the servers the config names (or the ones the preset expands to) and resolves to the session object. When manageConnections.waitForConnections is set, it polls connections until every server reports connected or the wait times out; an empty connection list never counts as "all connected".

ParameterTypeRequiredDescription
userIdstringyesYour identifier for the end user this session acts for
configSessionConfignoServers or preset, connection wait, metadata, project scope, test-mode mocks
Example
const  = await .("user_0000", {
  : ["asaas", "melhor-envio"],
  : { : true, : 30000 },
  : { : "ord_0000" },
});
Result: Session
import type { SessionBase } from "@codespar/types";
// ---cut---
// @codespar/types: what the type declares.
interface Session extends SessionBase {
  readonly id: string;
  readonly status: "active" | "closed" | "error";
  mcp?: { url: string; headers: Record<string, string> };
  // ...and the methods on the Session, Money, Status and Connections pages
}

// The object the SDK builds also has, untyped on the interface:
//   userId: string; servers: string[]; createdAt: Date

Throws a ZodError from SessionConfigSchema when the config is malformed (an unknown preset, a project id in the wrong format, a mock value that is not an object or array of objects); a CodesparApiError when the backend answers non-2xx (status, code and the parsed body on e.body) or cannot be reached (status: 0); a TimeoutError when the request exceeds the client timeout.

Related Sessions, Test mode and mocks, REST POST /v1/sessions.

SessionConfig

interface SessionConfig {
  /** Servers to connect, by id (e.g. "zoop", "nuvem-fiscal") */
  servers?: string[];
  /** "brazilian" enables the BR commerce servers */
  preset?: "brazilian" | "mexican" | "argentinian" | "colombian" | "all";
  manageConnections?: {
    /** Block until all servers are connected */
    waitForConnections?: boolean;
    /** Timeout in ms for the connection wait. Default: 30000 */
    timeout?: number;
  };
  /** Attached to every tool call in this session */
  metadata?: Record<string, string>;
  /** Overrides the client's projectId for this session */
  projectId?: string;
  /** Test-mode mocks, keyed by canonical tool name (`asaas/create_payment`) */
  mocks?: Record<string, MockValue>;
}

type MockObject = Record<string, unknown>;
type MockValue = MockObject | MockObject[];

servers wins over preset when both are given. Mock keys are forwarded verbatim: the double-underscore form (asaas__create_payment) reaches the backend unrewritten and comes back as mocks_invalid, by design. Mocks need a csk_test_ key against a test project; otherwise the backend refuses with mocks_not_permitted.

SessionConfigSchema

ReadSessionConfigSchema: z.ZodObject
not in the Python package

The zod schema create validates its config with. Exported so a caller can validate a config it received from elsewhere before opening a session, with the same rules the client applies.

import {  } from "@codespar/sdk";

const  = .({ : "brazilian" });
if (!.) .(..);

api

Readreadonly api: ApiClient
since 0.12.0not in the Python package

The generated REST client, sharing this client's key, base URL, project scope and default timeout. Every operation of the OpenAPI document is a typed call on it; the REST client pages list them by group.

const wallet = await ..("/v1/wallets/{id}", {
const wallet: {
    id: string;
    org_id: string;
    project_id: string;
    agent_id: string | null;
    display_name: string;
    status: "active" | "frozen" | "closed";
    created_at: string;
    closed_at: string | null;
    metadata: {
        [key: string]: unknown;
    };
    balances?: components["schemas"]["WalletBalance"][];
}
: { : "wlt_0000000000000000" }, });

Ships since @codespar/sdk 0.12.0. It types every operation of the document its release was generated from, so when the API ships a route ahead of a release the new one appears in the REST pages without a typed call until the next publish. The REST client pages say which ones those are today.

payables

Readreadonly payables: Payables
since 0.16.19Pythonpayables

Documents and batches to pay: payables.files.upload(bytes, { filename }) reads a PDF, an image or a CSV/XLSX list on the API's side and answers a file_id; payables.batches.create({ fileIds | items }, { idempotencyKey }) turns files and typed items into one batch with what the rail resolved per item; payables.batches.get, payables.batches.updateItem(batchId, itemId, { expectedVersion, ... }) and payables.batches.pay(batchId, { version, listHash, mandateId }, { idempotencyKey }) review, correct and confirm the exact list. Extracting never pays: pay needs the version and list hash of the list the caller saw, and answers 409 with the current batch when they moved (see payableBatchFromError). The journeys are in the cookbook Pay documents and batches.

const  = await ...(, { : "conta.pdf" });
const batch = await ...({ : [.] }, { : "conta-2026-11" });
const batch: PayableBatchCreated

Ships since @codespar/sdk 0.16.19 and codespar (Python) 0.13.0.

wallet

Readreadonly wallet: Wallet
since 0.16.21Pythonwallet

A consumer's own account. wallet.pixKeys.list(consumerId) reads the account's Pix keys from the bank (account_masked, keys[] with key and key_type, count); wallet.pixKeys.register(consumerId, { keyType, key? }) registers one key with the type explicit, EVP included (a random key is never minted by omission; a test project's own account registers only EVP); wallet.pixKeys.delete(consumerId, key, { confirm: true }) deletes one. A delete without { confirm: true } throws PixKeyDeleteNotConfirmedError (pix_key_delete_requires_confirmation, carrying the consequence sentence) before any request. These are the routes under /v1/consumers/:consumerId/pix-keys; the conversation-shaped surface, with key_id and key_tail instead of the key value, is the codespar_wallet meta-tool.

const  = await ...("sbx_prj_0000000000000000");
const  = await ...("sbx_prj_0000000000000000", { : "EVP" });
await cs...("sbx_prj_0000000000000000", ., { : true });
const cs: CodeSpar

Ships since @codespar/sdk 0.16.21 and codespar (Python) 0.14.0 (cs.wallet.pix_keys, confirm=True).

receipts

Readreadonly receipts: Receipts
since 0.16.22Pythonreceipts

The documents a confirmed payment leaves behind. receipts.document(receiptId, { format? }) downloads the comprovante of the payment the receipt seals, as pdf (default, one page of 600×828 pt) or png (the same page as an image, 2×, for sharing in a conversation); the answer is a Document with bytes, contentType and the filename the server named (comprovante-<receiptId>.pdf). The route is GET /v1/consumers/receipts/{id}/document?format=pdf|png, under the receipts:read scope: it reads the confirmed record and moves no money. Before the payment is confirmed it answers 409 document_not_final (a CodesparApiError here), and while the renderer is down, 503 document_renderer_unavailable; a format other than pdf or png is refused before any request. The header X-CodeSpar-Document-Sha256 carries the hash of the data the page was rendered from, the same value the codespar_wallet meta-tool answers as sha256.

const  = await ..("rcpt_0000000000000000", { : "png" });
await writeFile(., .);
function writeFile(file: PathLike | FileHandle, data: string | NodeJS.ArrayBufferView | Iterable<string | NodeJS.ArrayBufferView> | AsyncIterable<string | NodeJS.ArrayBufferView> | Stream, options?: (ObjectEncodingOptions & {
    mode?: Mode | undefined;
    flag?: OpenMode | undefined;
    flush?: boolean | undefined;
} & EventEmitter<T extends EventMap<T> = DefaultEventMap>.Abortable) | BufferEncoding | null): Promise<void>

Asynchronously writes data to a file, replacing the file if it already exists. data can be a string, a buffer, an AsyncIterable, or an Iterable object.

The encoding option is ignored if data is a buffer.

If options is a string, then it specifies the encoding.

The mode option only affects the newly created file. See fs.open() for more details.

Any specified FileHandle has to support writing.

It is unsafe to use fsPromises.writeFile() multiple times on the same file without waiting for the promise to be settled.

Similarly to fsPromises.readFile - fsPromises.writeFile is a convenience method that performs multiple write calls internally to write the buffer passed to it. For performance sensitive code consider using fs.createWriteStream() or filehandle.createWriteStream().

It is possible to use an AbortSignal to cancel an fsPromises.writeFile(). Cancelation is "best effort", and some amount of data is likely still to be written.

import { writeFile } from 'node:fs/promises';
import { Buffer } from 'node:buffer';

try {
  const controller = new AbortController();
  const { signal } = controller;
  const data = new Uint8Array(Buffer.from('Hello Node.js'));
  const promise = writeFile('message.txt', data, { signal });

  // Abort the request before the promise settles.
  controller.abort();

  await promise;
} catch (err) {
  // When a request is aborted - err is an AbortError
  console.error(err);
}

Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.writeFile performs.

@sincev10.0.0@paramfile filename or FileHandle@returnFulfills with undefined upon success.

Ships since @codespar/sdk 0.16.22 and codespar (Python) 0.15.1 (cs.receipts.document(receipt_id, format="png")).

account

Readreadonly account: Account
since 0.16.22Pythonaccount

The project's account on paper. account.statement({ from, to, currency? }) downloads the extrato of the period as an A4 PDF: opening balance, inflows, outflows and closing balance, reconciled on the server (the identity opening + inflows − outflows = closing is asserted against an independent reading of the ledger, and a period that does not close answers 500 statement_not_reconciled instead of a wrong page), with the reserves (holds) shown apart from the identity and the entries listed by day. from and to are calendar days (YYYY-MM-DD, America/São Paulo), to inclusive and not after today, at most 92 days after from; currency defaults to BRL. The route is GET /v1/account/statement?from&to&format=pdf[&currency], under wallets:read; format accepts only pdf. The existing CSV export of the Wallet page is unchanged; this is the document a person sends to an accountant.

const  = await ..({ : "2026-09-01", : "2026-09-30" });
await writeFile(., .); // extrato-2026-09-01-2026-09-30.pdf
function writeFile(file: PathLike | FileHandle, data: string | NodeJS.ArrayBufferView | Iterable<string | NodeJS.ArrayBufferView> | AsyncIterable<string | NodeJS.ArrayBufferView> | Stream, options?: (ObjectEncodingOptions & {
    mode?: Mode | undefined;
    flag?: OpenMode | undefined;
    flush?: boolean | undefined;
} & EventEmitter<T extends EventMap<T> = DefaultEventMap>.Abortable) | BufferEncoding | null): Promise<void>

Asynchronously writes data to a file, replacing the file if it already exists. data can be a string, a buffer, an AsyncIterable, or an Iterable object.

The encoding option is ignored if data is a buffer.

If options is a string, then it specifies the encoding.

The mode option only affects the newly created file. See fs.open() for more details.

Any specified FileHandle has to support writing.

It is unsafe to use fsPromises.writeFile() multiple times on the same file without waiting for the promise to be settled.

Similarly to fsPromises.readFile - fsPromises.writeFile is a convenience method that performs multiple write calls internally to write the buffer passed to it. For performance sensitive code consider using fs.createWriteStream() or filehandle.createWriteStream().

It is possible to use an AbortSignal to cancel an fsPromises.writeFile(). Cancelation is "best effort", and some amount of data is likely still to be written.

import { writeFile } from 'node:fs/promises';
import { Buffer } from 'node:buffer';

try {
  const controller = new AbortController();
  const { signal } = controller;
  const data = new Uint8Array(Buffer.from('Hello Node.js'));
  const promise = writeFile('message.txt', data, { signal });

  // Abort the request before the promise settles.
  controller.abort();

  await promise;
} catch (err) {
  // When a request is aborted - err is an AbortError
  console.error(err);
}

Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.writeFile performs.

@sincev10.0.0@paramfile filename or FileHandle@returnFulfills with undefined upon success.

Ships since @codespar/sdk 0.16.22 and codespar (Python) 0.15.1 (cs.account.statement("2026-09-01", "2026-09-30")).

CodeSpar client | CodeSpar