Skip to main content
API reference

Sessions

Generated HTTP reference for the 12 operations the published OpenAPI document describes under sessions.

13 min read
View MarkdownEdit on GitHub

Sessions

This page is generated from the published OpenAPI document. It is complete with respect to that document and says nothing about surfaces the document does not describe yet. See what is generated here for what that means.

Base URL: https://api.codespar.dev

Every operation below requires a Bearer token. See Authentication.

Base URL: https://api.codespar.dev

All endpoints require authentication via Bearer token. See Authentication for details on API key types and scopes.

Authorization: Bearer csk_live_your_api_key

Project scoping

Every /v1 endpoint accepts an optional x-codespar-project header that pins the request to a specific project within your account.

HeaderRequiredDescription
x-codespar-projectNoProject ID in the form prj_<16chars>. If omitted, requests resolve to the account's default project (auto-created at signup). Project-scoped API keys ignore this header and always use the key's pinned project.
# Explicit project
curl -X POST https://api.codespar.dev/v1/sessions \
  -H "Authorization: Bearer csk_live_abc123..." \
  -H "x-codespar-project: prj_a1b2c3d4e5f6g7h8" \
  -H "Content-Type: application/json" \
  -d '{"servers": ["stripe"]}'

# Omitted -- falls back to the account's default project
curl -X POST https://api.codespar.dev/v1/sessions \
  -H "Authorization: Bearer csk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{"servers": ["stripe"]}'

Sessions, triggers, API keys, connections, and events are all scoped to the resolved project. See Projects concept and the Projects API for details.


POST /v1/sessions

Creates a new session connected to the specified MCP servers. Returns the session object with connection status for each server.

Auth required: Yes (scope: sessions:create)

Request body

FieldTypeRequiredDescription
user_idstringYesEnd-user identifier on behalf of whom the agent acts
serversstring[]Yes*List of server identifiers (e.g., ["stripe", "mercadopago"])
presetstringNoNamed preset: brazilian, mexican, argentinian, colombian, all
manageConnectionsobjectNoConnection-management options (see Sessions)
metadataobjectNoKey-value metadata attached to every tool call

*Required unless preset is specified. Can be combined with preset to add additional servers.

curl example

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"]
  }'

Response -- 201 Created

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

SDK equivalent

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

Sessions expire after 30 minutes of inactivity. The expires_at timestamp is updated with each tool call. If a server fails to connect, the session is still created with the remaining servers -- check the status field on each server entry.


GET /v1/sessions

Lists all sessions for your account. Supports pagination and filtering by status.

Auth required: Yes (scope: sessions:read)

Query parameters

ParameterTypeDefaultDescription
statusstring--Filter by status: active, closed, error
limitnumber20Results per page (max 100)
offsetnumber0Pagination offset

curl example

curl "https://api.codespar.dev/v1/sessions?status=active&limit=10" \
  -H "Authorization: Bearer csk_live_abc123..."

Response -- 200 OK

{
  "data": [
    {
      "id": "ses_abc123def456",
      "status": "active",
      "servers": ["stripe", "mercadopago"],
      "tool_calls": 12,
      "created_at": "2026-04-15T10:30:00Z",
      "expires_at": "2026-04-15T11:00:00Z"
    },
    {
      "id": "ses_def789ghi012",
      "status": "active",
      "servers": ["correios", "nfe"],
      "tool_calls": 3,
      "created_at": "2026-04-15T10:15:00Z",
      "expires_at": "2026-04-15T10:45:00Z"
    }
  ],
  "total": 47,
  "limit": 10,
  "offset": 0
}

GET /v1/sessions/:id

Retrieves details about an existing session, including connected servers, tool call count, and expiry.

Auth required: Yes (scope: sessions:read)

curl example

curl https://api.codespar.dev/v1/sessions/ses_abc123def456 \
  -H "Authorization: Bearer csk_live_abc123..."

Response -- 200 OK

{
  "id": "ses_abc123def456",
  "status": "active",
  "servers": [
    { "id": "stripe", "name": "Stripe", "status": "connected" },
    { "id": "mercadopago", "name": "Mercado Pago", "status": "connected" }
  ],
  "tool_calls": 12,
  "created_at": "2026-04-15T10:30:00Z",
  "expires_at": "2026-04-15T11:00:00Z"
}

DELETE /v1/sessions/:id

Closes an active session and releases all server connections. Closed sessions cannot be reopened; create a new session instead.

Auth required: Yes

curl example

curl -X DELETE https://api.codespar.dev/v1/sessions/ses_abc123def456 \
  -H "Authorization: Bearer csk_live_abc123..."

Response -- 200 OK

{
  "id": "ses_abc123def456",
  "status": "closed",
  "tool_calls": 12,
  "closed_at": "2026-04-15T10:45:00Z"
}

SDK equivalent

await session.close();

Closing a session is idempotent. Calling DELETE on an already-closed session returns 200 OK with the existing closed state.


POST /v1/sessions/:id/execute

Executes a tool call synchronously. The request blocks until the tool completes and the result is available. Use this for operations where the agent needs the response before continuing.

Auth required: Yes

Request body

FieldTypeRequiredDescription
namestringYesTool name (e.g., codespar_pay, stripe_create_refund)
argumentsobjectYesTool arguments matching the tool's input_schema

curl example

curl -X POST https://api.codespar.dev/v1/sessions/ses_abc123/execute \
  -H "Authorization: Bearer csk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "codespar_pay",
    "arguments": {
      "method": "pix",
      "amount": 9990,
      "currency": "BRL",
      "description": "Order #1234",
      "customer_email": "maria@example.com"
    }
  }'

Response -- 200 OK

{
  "tool_call_id": "tc_xyz789abc",
  "name": "codespar_pay",
  "result": {
    "payment_id": "pay_xyz789",
    "status": "pending",
    "method": "pix",
    "provider": "asaas",
    "pix_code": "00020126580014br.gov.bcb.pix0136a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "qr_code_url": "https://api.codespar.dev/qr/pay_xyz789.png",
    "amount": 9990,
    "currency": "BRL",
    "expires_at": "2026-04-15T11:00:00Z"
  },
  "execution_time_ms": 342
}

SDK equivalent

const result = await session.execute("codespar_pay", {
  method: "pix",
  amount: 9990,
  currency: "BRL",
});

Each call to this endpoint counts as one tool call for billing purposes. If the tool fails (e.g., provider error), it still counts as a tool call.


POST /v1/sessions/:id/send

Sends a natural-language message. The CodeSpar backend runs a Claude tool-use loop using the session's connected servers, calling whichever tools the agent decides it needs, and returns the final response along with every tool call made. Use this for the simplest possible agent integration, with no client-side orchestration.

Auth required: Yes

Request body

FieldTypeRequiredDescription
messagestringYesNatural-language instruction for the agent

curl example

curl -X POST https://api.codespar.dev/v1/sessions/ses_abc123/send \
  -H "Authorization: Bearer csk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Charge R$150 via Pix for order #5678 and send a WhatsApp confirmation"
  }'

Response -- 200 OK

{
  "message": "Done. Pix QR code generated and WhatsApp message sent.",
  "tool_calls": [
    { "id": "tc_1", "tool_name": "codespar_pay", "status": "success", "duration_ms": 412 },
    { "id": "tc_2", "tool_name": "codespar_notify", "status": "success", "duration_ms": 287 }
  ],
  "iterations": 2
}

Streaming variant

Streaming is content-negotiated on the same endpoint: send Accept: text/event-stream on POST /v1/sessions/:id/send to receive an SSE stream of StreamEvents (assistant text, tool use, tool result, done) -- see the SDK reference for event shapes.

SDK equivalent

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

GET /v1/sessions/:id/connections

Lists OAuth connections for a session created with manageConnections: true. Returns the connection status and authorization URL for each server.

Auth required: Yes

curl example

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

Response -- 200 OK

{
  "connections": [
    {
      "server": "stripe",
      "status": "connected",
      "connected_at": "2026-04-15T10:31:00Z"
    },
    {
      "server": "mercadopago",
      "status": "pending",
      "authUrl": "https://codespar.dev/connect/mercadopago?session=ses_abc123"
    }
  ]
}
Connection statusDescription
pendingUser has not yet authenticated. The authUrl field contains the OAuth URL.
connectedUser has authenticated. Tool calls to this server use the user's credentials.
expiredOAuth token has expired. A new authUrl is provided for re-authentication.
revokedUser revoked access. A new authUrl is provided.

SDK equivalent

const connections = await session.connections();

POST /v1/sessions/:id/tool-calls

Records a tool call result from an external execution. This is used in advanced workflows where the tool is executed outside of CodeSpar (e.g., by the LLM framework) and the result needs to be recorded for auditing and billing.

Auth required: Yes (scope: tools:execute)

Request body

FieldTypeRequiredDescription
namestringYesTool name that was called
argumentsobjectYesArguments that were passed to the tool
resultobjectYesResult returned by the tool

curl example

curl -X POST https://api.codespar.dev/v1/sessions/ses_abc123/tool-calls \
  -H "Authorization: Bearer csk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "codespar_pay",
    "arguments": {"method": "pix", "amount": 5000, "currency": "BRL"},
    "result": {"payment_id": "pay_ext_001", "status": "completed"}
  }'

Response -- 201 Created

{
  "id": "tc_rec_abc123",
  "session_id": "ses_abc123",
  "name": "codespar_pay",
  "status": "recorded",
  "recorded_at": "2026-04-15T10:50:00Z"
}

GET /v1/sessions/:id/tool-calls

Lists all tool calls made within a session. Useful for auditing and debugging agent behavior.

Auth required: Yes (scope: sessions:read)

Query parameters

ParameterTypeDefaultDescription
limitnumber100Rows to return, newest first (min 1, max 500)

limit is the only query parameter. There is no offset and no server-side filter by status, server, tool, or date range: the endpoint returns the newest limit rows for the session and you filter client-side.

curl example

curl "https://api.codespar.dev/v1/sessions/ses_abc123/tool-calls?limit=5" \
  -H "Authorization: Bearer csk_live_abc123..."

Response -- 200 OK

{
  "tool_calls": [
    {
      "id": "tc_001",
      "session_id": "ses_abc123",
      "server_id": "codespar",
      "tool_name": "codespar_discover",
      "status": "success",
      "duration_ms": 67,
      "error_code": null,
      "input": { "domain": "payments" },
      "output": { "servers": ["asaas", "stripe"] },
      "called_at": "2026-04-15T10:30:05Z"
    },
    {
      "id": "tc_002",
      "session_id": "ses_abc123",
      "server_id": "asaas",
      "tool_name": "codespar_pay",
      "status": "success",
      "duration_ms": 342,
      "error_code": null,
      "input": { "method": "pix", "amount": 9990, "currency": "BRL" },
      "output": { "id": "pay_z8rwa1qnr0twili5", "status": "PENDING" },
      "called_at": "2026-04-15T10:30:12Z"
    }
  ]
}

The envelope carries tool_calls and nothing else: no total, no limit, no offset echo. status is running on a call recorded but not yet finalized, then success or error. Two further keys, routing and failover_trail, appear on a row only when a routing decision was recorded for it.


PATCH /v1/sessions/:id/tool-calls/:tc_id

Updates the status or metadata of a recorded tool call. Used to mark externally-executed tool calls as completed or failed.

Auth required: Yes

Request body

FieldTypeRequiredDescription
statusstringNoNew status: completed, failed
resultobjectNoUpdated result object
errorobjectNoError details if the tool call failed

curl example

curl -X PATCH https://api.codespar.dev/v1/sessions/ses_abc123/tool-calls/tc_rec_abc123 \
  -H "Authorization: Bearer csk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "status": "completed",
    "result": {
      "payment_id": "pay_ext_001",
      "status": "paid",
      "paid_at": "2026-04-15T10:51:00Z"
    }
  }'

Response -- 200 OK

{
  "id": "tc_rec_abc123",
  "session_id": "ses_abc123",
  "name": "codespar_pay",
  "status": "completed",
  "result": {
    "payment_id": "pay_ext_001",
    "status": "paid",
    "paid_at": "2026-04-15T10:51:00Z"
  },
  "updated_at": "2026-04-15T10:51:05Z"
}

GET /v1/health

Consolidated health check across the six router subsystems: db, vault, embeddings, fx_rates, telemetry, connections. Always returns 200 OK regardless of individual check status: monitors should parse the status field, not the HTTP code.

Auth required: Yes (dual-auth: API key or service key).

curl example

curl https://api.codespar.dev/v1/health \
  -H "Authorization: Bearer csk_live_abc123..."

Response -- 200 OK

{
  "status": "healthy",
  "checks": {
    "db": { "status": "healthy", "latency_ms": 12 },
    "vault": { "status": "healthy", "latency_ms": 8 },
    "embeddings": { "status": "healthy", "latency_ms": 41 },
    "fx_rates": { "status": "healthy", "stale_seconds": 312 },
    "telemetry": { "status": "healthy" },
    "connections": { "status": "healthy", "count": 47 }
  },
  "schema_version": { "current": 64, "expected": 64 },
  "observed_at": "2026-05-04T18:30:00Z"
}

The top-level status rolls up to healthy, degraded, or down. State transitions emit system.health.degraded and system.health.recovered events to operator webhooks.


GET /health

Unauthenticated liveness probe. No subsystem detail; use /v1/health for that.

curl example

curl https://api.codespar.dev/health

Response -- 200 OK

{
  "status": "ok",
  "uptime_ms": 8421305
}

Async settlement

codespar_charge, codespar_pay, and codespar_kyc return immediately with a tool_call_id. Settlement happens on the provider's clock: Pix in seconds, cards in minutes, Boleto and ACH in days. Blocking the agent's request for that window is not workable, so the tool call and the settlement are decoupled. You poll or stream the status endpoints below until a terminal state.

Correlation chain

Three identifiers connect a tool call to the provider webhook that settles it:

  1. tool_call_id: returned by the SDK or POST /v1/sessions/:id/execute. Opaque. Use it as the path parameter on every status endpoint.
  2. idempotency_key: a UUID the backend generates, stores on the tool-call record, and forwards upstream in the provider's idempotency or external-reference field.
  3. external_reference: what the provider echoes back in its webhook payload.

When the webhook arrives, the backend normalizes it into an event keyed by external_reference and matches that against the tool call's idempotency_key. Until a matching event lands, the status endpoints return { "status": "pending" }.

Where the idempotency key lands, per provider

The backend writes the same UUID into whichever field the provider supports. You only need this table when debugging a webhook that did not correlate.

ProviderField
AsaasexternalReference body field, echoed on every webhook
Mercado PagoX-Idempotency-Key header plus external_reference body field
StripeIdempotency-Key header, surfaced on the resulting object's metadata
iuguidempotency_key body field, echoed on webhooks
Stoneidempotency_key body field, echoed on webhooks

One caveat: Mercado Pago's webhook payload omits external_reference and carries only the payment ID. On receipt, the backend fetches the payment from the Mercado Pago API (5 second timeout) to recover the reference before normalizing. If that fetch fails, the event lands without a reference and the status endpoint keeps returning pending until reconciled. Nothing to configure; noted here so the missing field in MP's own webhook docs does not surprise you.

Polling or streaming

Both read the same events, so they always agree. Poll (payment-status, verification-status) for one-off checks and batch reconciliation jobs that walk many tool calls on a schedule. Stream for live UX and long settlement windows where latency to terminal matters; see Streaming status.


Streaming status

Two SDK methods push settlement state over Server-Sent Events instead of polling:

  • session.paymentStatusStream(toolCallId, opts) for codespar_charge / codespar_pay
  • session.verificationStatusStream(toolCallId, opts) for codespar_kyc

Both wrap a single GET to /v1/tool-calls/:id/<status>/stream that opens a long-lived text/event-stream response. The wrapper parses frames, fires callbacks, and resolves on terminal.

Event shape

EventWhenPayload
snapshotOnce, immediately on connectCurrent state of the tool call, often pending
updateOn each state change after connect; zero or moreThe new status envelope
doneOnce, 5 seconds after the state goes terminal, then the connection closesThe final envelope

snapshot is guaranteed first, done guaranteed last. A frame on the wire:

event: update
data: {"status":"completed","tool_call_id":"tc_xyz789","final_amount_minor":9990,"settled_at":"2026-04-15T10:35:12Z"}

Heartbeats

Every 15 seconds the server emits a comment frame:

: heartbeat 1713178215000

Heartbeats keep proxies from idle-closing quiet streams. Comment frames are not events: clients scanning for event: lines skip them naturally, and the TypeScript and Python wrappers filter them so your update callback never fires on a heartbeat.

Callbacks and cancellation

Awaiting the method resolves with the final envelope. Pass onUpdate to observe every transition, and an AbortSignal to drop the stream before terminal:

const ac = new AbortController();
setTimeout(() => ac.abort(), 60_000); // give up after 60s

const final = await session.paymentStatusStream(charge.tool_call_id, {
  onUpdate: (env) => console.log(env.observed_at, env.status),
  signal: ac.signal, // rejects with AbortError if aborted before terminal
});

In Python, payment_status_stream takes on_update and cancels like any awaitable:

task = asyncio.create_task(
    session.payment_status_stream(charge["tool_call_id"], on_update=print),
)
try:
    final = await asyncio.wait_for(task, timeout=60)
except asyncio.TimeoutError:
    task.cancel()  # status not yet terminal

A synchronous wrapper on Session blocks the calling thread until terminal, for non-async callers.

Aborting the stream does not cancel the payment or the verification; it only stops watching. State lives server-side, so you can reconnect or fall back to polling at any time.


GET /v1/tool-calls/:id/payment-status

Polling endpoint for async payment settlement against codespar_charge and codespar_pay tool calls. Returns { status: "pending" } until the provider webhook correlates the call (see Async settlement); on settlement, returns the final amount and settlement timestamp.

Auth required: Yes

curl example

curl https://api.codespar.dev/v1/tool-calls/tc_xyz789/payment-status \
  -H "Authorization: Bearer csk_live_abc123..."

Response -- 200 OK (settled)

{
  "status": "completed",
  "idempotency_key": "idem_5f3a...",
  "external_reference": "asaas_pay_abc123",
  "final_amount_minor": 9990,
  "settled_at": "2026-04-15T10:35:12Z"
}

Response -- 200 OK (pending)

{
  "status": "pending"
}

SDK equivalent

const status = await session.paymentStatus("tc_xyz789");

GET /v1/tool-calls/:id/payment-status/stream

Server-Sent Events variant of payment-status. Emits snapshot, update, and done events with a 15s comment heartbeat; see Streaming status for the full event contract, callbacks, and cancellation. The polling sibling stays available, clients pick whichever fits their runtime.

Auth required: Yes

curl example

curl -N https://api.codespar.dev/v1/tool-calls/tc_xyz789/payment-status/stream \
  -H "Authorization: Bearer csk_live_abc123..."

Stream output

event: snapshot
data: {"status":"pending"}

event: update
data: {"status":"completed","final_amount_minor":9990,"settled_at":"2026-04-15T10:35:12Z"}

event: done
data: {"status":"completed"}

SDK equivalent

await session.paymentStatusStream("tc_xyz789", {
  onUpdate: (s) => console.log(s.status),
});

GET /v1/tool-calls/:id/verification-status

Polling endpoint for async KYC settlement against codespar_kyc inquiries. Status priority is approved > rejected > review > expired > pending when multiple events have been recorded.

Auth required: Yes

curl example

curl https://api.codespar.dev/v1/tool-calls/tc_kyc456/verification-status \
  -H "Authorization: Bearer csk_live_abc123..."

Response -- 200 OK

{
  "status": "approved",
  "idempotency_key": "idem_kyc_a1b2...",
  "external_reference": "persona_inq_xyz",
  "settled_at": "2026-04-15T10:36:00Z"
}

SDK equivalent

const status = await session.verificationStatus("tc_kyc456");

GET /v1/tool-calls/:id/verification-status/stream

SSE variant of verification-status. Same event contract as the payment-status stream (see Streaming status), with the verification terminal vocabulary (approved, rejected, review, expired). Polling sibling stays available.

Auth required: Yes

curl example

curl -N https://api.codespar.dev/v1/tool-calls/tc_kyc456/verification-status/stream \
  -H "Authorization: Bearer csk_live_abc123..."

SDK equivalent

await session.verificationStatusStream("tc_kyc456", {
  onUpdate: (s) => console.log(s.status),
});

GET /v1/meta-tools/stats

Per-(provider × canonical_tool) router observability rollup. Reports attempt counts, success counts, and p50 latency for each rail in META_TOOL_CATALOG. Powers the /dashboard/router observability page.

Auth required: Operator/service auth only. This is a dashboard-internal observability rollup, not part of the agent (Bearer-key) surface: a csk_ API key answers 401, and the credential that does open it is CodeSpar's platform secret, which never leaves our infrastructure. Read this rollup at /dashboard/router; the shape below is what that page renders.

Request

GET /v1/meta-tools/stats

Response -- 200 OK

{
  "rows": [
    {
      "canonical_tool": "codespar_pay",
      "provider_id": "asaas",
      "attempts": 1284,
      "successes": 1271,
      "p50_ms": 412
    },
    {
      "canonical_tool": "codespar_charge",
      "provider_id": "mercadopago",
      "attempts": 902,
      "successes": 897,
      "p50_ms": 318
    }
  ]
}

GET /v1/meta-tools/stats/hourly

Same shape as /v1/meta-tools/stats but bucketed into the last 24 hourly windows for a single provider+tool pair. Used to render router latency/error sparklines.

Auth required: Operator/service auth only (dashboard-internal; not callable with a csk_ API key).

Query parameters

ParameterTypeRequiredDescription
provider_idstringYesProvider identifier (e.g., asaas)
canonical_toolstringYesCanonical meta-tool (e.g., codespar_pay)

Request

GET /v1/meta-tools/stats/hourly?provider_id=asaas&canonical_tool=codespar_pay

Response -- 200 OK

{
  "provider_id": "asaas",
  "canonical_tool": "codespar_pay",
  "buckets": [
    { "hour": "2026-05-04T18:00:00Z", "attempts": 54, "successes": 53, "p50_ms": 408 },
    { "hour": "2026-05-04T17:00:00Z", "attempts": 61, "successes": 60, "p50_ms": 412 }
  ]
}

POST /v1/connections/hmac-validate

Round-trip validation for the hmac_signed auth_type. The dashboard calls this when an operator pastes a key + secret pair into the connect modal: the backend signs a probe request against the provider and reports whether the credentials produced a valid signature on the wire.

Auth required: Yes

Request body

FieldTypeRequiredDescription
server_idstringYesProvider identifier (e.g., foxbit)
keystringYesSigning key
secretstringYesSigning secret

curl example

curl -X POST https://api.codespar.dev/v1/connections/hmac-validate \
  -H "Authorization: Bearer csk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "server_id": "foxbit",
    "key": "fx_key_abc",
    "secret": "fx_secret_xyz"
  }'

Response -- 200 OK

{
  "valid": true,
  "probed_endpoint": "GET /rest/v3/me"
}

Response -- 200 OK (invalid)

{
  "valid": false,
  "probed_endpoint": "GET /rest/v3/me",
  "provider_status": 401,
  "provider_message": "Invalid signature"
}

Error responses

All endpoints follow a consistent error format:

{
  "error": "error_code",
  "message": "Human-readable error description.",
  "status": 400
}
StatusError codeDescriptionResolution
400invalid_requestMissing required fields or invalid valuesCheck the request body against the schema
401unauthorizedInvalid or missing API keyVerify the Authorization header
403forbiddenAPI key lacks the required scopeCheck key scopes in the dashboard
404not_foundSession or resource not foundVerify the session ID; the session may have been closed
429rate_limitedToo many requestsWait and retry; check Retry-After header
429quota_exceededMonthly tool call quota exceededUpgrade your plan or wait for the next billing cycle
500internal_errorServer errorRetry with exponential backoff; contact support if persistent
503server_unavailableMCP server is temporarily unavailableThe specific provider may be down; retry or use an alternative server

Rate limit headers

Every response includes rate limit information:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 297
X-RateLimit-Reset: 1713178260

Next steps

Every operation, from the spec

Generated from the published OpenAPI document, so it never drifts from what the API actually serves. The section above is written by hand and carries what a schema cannot: the object model, field rules, and the order to call things in.

GET /v1/sessions

List sessions

Query parameters

NameTypeRequiredDescription
beforestringno
limitintegerno
status"active" | "closed" | "error"no
user_idstringno

Responses

StatusBodyDescription
200objectOK
400objectBad Request — the body or query did not match the schema.

Response 200

FieldTypeRequiredDescription
next_beforestring,nullyes
sessionsarray of Sessionyes

Example response

{
  "sessions": [
    {
      "id": "ses_0000000000000000",
      "org_id": "org_0000000000000000",
      "project_id": "prj_0000000000000000",
      "user_id": "user_0000000000000000",
      "servers": [
        "string"
      ],
      "status": "active",
      "created_at": "2026-01-15T12:00:00.000Z"
    }
  ]
}

Example request

curl -X GET https://api.codespar.dev/v1/sessions \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/sessions

Open a session

Request body

FieldTypeRequiredDescription
chaosobjectno
mocksobjectno
serversarray of stringyes
user_idstringno

Responses

StatusBodyDescription
201SessionOK
400object | objectBad Request — schema failure, or an unknown server id.
403objectOK
413objectOK

Response 201

FieldTypeRequiredDescription
closed_atstring,null (date-time)no
created_atstring (date-time)yes
idstringyesses_-prefixed
org_idstringyes
project_idstringyes
serversarray of stringyes
status"active" | "closed" | "error"yes
user_idstringyes

Example response

{
  "id": "ses_0000000000000000",
  "org_id": "org_0000000000000000",
  "project_id": "prj_0000000000000000",
  "user_id": "user_0000000000000000",
  "servers": [
    "string"
  ],
  "status": "active",
  "created_at": "2026-01-15T12:00:00.000Z"
}

Example request

curl -X POST https://api.codespar.dev/v1/sessions \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "servers": [
         "string"
       ],
       "user_id": "user_0000000000000000",
       "mocks": {},
       "chaos": {}
     }'

GET /v1/sessions/{id}

Read one session

Path parameters

NameTypeRequiredDescription
idstringyes

Responses

StatusBodyDescription
200objectOK
404objectNot Found

Response 200

FieldTypeRequiredDescription
closed_atstring,null (date-time)no
created_atstring (date-time)yes
idstringyesses_-prefixed
org_idstringyes
project_idstringyes
serversarray of stringyes
status"active" | "closed" | "error"yes
tool_calls_countintegeryes
user_idstringyes

Example response

{
  "id": "obj_0000000000000000",
  "org_id": "org_0000000000000000",
  "project_id": "prj_0000000000000000",
  "user_id": "user_0000000000000000",
  "servers": [
    "string"
  ],
  "status": "active",
  "created_at": "2026-01-15T12:00:00.000Z",
  "tool_calls_count": 1
}

Example request

curl -X GET https://api.codespar.dev/v1/sessions/{id} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

DELETE /v1/sessions/{id}

Close a session

Path parameters

NameTypeRequiredDescription
idstringyes

Responses

StatusBodyDescription
200objectOK
404objectNot Found

Response 200

FieldTypeRequiredDescription
closed_atstring,null (date-time)yes
idstringyes
status"closed"yes

Example response

{
  "id": "obj_0000000000000000",
  "status": "closed"
}

Example request

curl -X DELETE https://api.codespar.dev/v1/sessions/{id} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/sessions/{id}/connections

List a session's servers and the tools it can call

Path parameters

NameTypeRequiredDescription
idstringyes

Responses

StatusBodyDescription
200objectOK
404objectNot Found

Response 200

FieldTypeRequiredDescription
serversarray of objectyes
toolsarray of objectyes

Example response

{
  "servers": [
    {
      "id": "obj_0000000000000000",
      "name": "Example",
      "category": "string",
      "country": "string",
      "auth_type": "string",
      "connected": true
    }
  ],
  "tools": [
    {
      "name": "Example",
      "description": "string",
      "input_schema": {
        "type": "object",
        "properties": {},
        "required": [
          "string"
        ]
      },
      "server": "codespar"
    }
  ]
}

Example request

curl -X GET https://api.codespar.dev/v1/sessions/{id}/connections \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/sessions/{id}/execute

Run one tool in the session

Path parameters

NameTypeRequiredDescription
idstringyes

Request body

FieldTypeRequiredDescription
estimatedCostnumberno
inputobjectno
paramsobjectno
toolstringyes

Responses

StatusBodyDescription
200object | objectOK. The full envelope, or the short unregistered-tool envelope that carries no tool_call_id and no called_at.
400objectBad Request — the body or query did not match the schema.
403object | objectForbidden — either a policy rule refused the call, or the org's monthly tool-call allowance is spent. The two bodies are disjoint: the policy one is \{ reason, ruleType, ruleId \} and carries NO error key (plus approval_id and expires_at when the refusal opened a pending approval); the quota one is \{ error: "quota_exceeded", ... \}.
404objectNot Found
409objectConflict — the session is not active, so it dispatches nothing.
422objectUnprocessable — the session declares mocks and this tool has none left, or none at all. tool_name is present only on tool_not_mocked. Reached from the catalog branch; a meta-tool never answers 422.
503object | objectService Unavailable — the route's policy guard could not answer (\{ error: "policy_engine_error" \}), or the mock engine failed (\{ code: "mocks_engine_error", message \}). Two different bodies at the same status.

Example response

{
  "success": true,
  "duration": 0,
  "server": "string",
  "tool": "string",
  "tool_call_id": "tc_0000000000000000",
  "called_at": "string"
}

Example request

curl -X POST https://api.codespar.dev/v1/sessions/{id}/execute \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "tool": "string",
       "params": {},
       "input": {},
       "estimatedCost": 0
     }'

GET /v1/sessions/{id}/mocks

Read a session's declared mocks and their consume counters

Path parameters

NameTypeRequiredDescription
idstringyes

Responses

StatusBodyDescription
200objectOK
404objectNot Found

Response 200

FieldTypeRequiredDescription
countersobjectyes
mocksobject,nullyes

Example response

{
  "counters": {}
}

Example request

curl -X GET https://api.codespar.dev/v1/sessions/{id}/mocks \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/sessions/{id}/proxy_execute

Make one raw HTTP call to a connected server

Path parameters

NameTypeRequiredDescription
idstringyes

Request body

FieldTypeRequiredDescription
bodyno
endpointstringyes
estimatedCostnumberno
headersobjectno
method"GET" | "POST" | "PUT" | "PATCH" | "DELETE"yes
paramsobjectno
serverstringyes

Responses

StatusBodyDescription
200objectOK
400object | objectBad Request — the body did not match the schema, or server is not one of the ids this session was opened on. The second body names the connected servers and points at the pre-connected sandbox meta-tool instead.
403object | objectForbidden — either a policy rule refused the call, or the org's monthly tool-call allowance is spent. The two bodies are disjoint: the policy one is \{ reason, ruleType, ruleId \} and carries NO error key (plus approval_id and expires_at when the refusal opened a pending approval); the quota one is \{ error: "quota_exceeded", ... \}.
404objectNot Found
409objectConflict — the session is not active, so it dispatches nothing.
413objectPayload Too Large — the serialized tool input exceeded the policy engine's cap under an approval-required rule. Not a policy denial: 403 and 413 are kept apart so a client can tell "refused" from "too big".
424objectFailed Dependency — no usable credential for this server. reason is the resolver's own outcome.
429objectToo Many Requests — the per-(org, server) bucket is empty. See the Retry-After header.
502objectBad Gateway — the upstream call itself failed (transport, not status). The attempt is still logged and chained, and proxy_call_id names the row.
503objectService Unavailable — the policy engine could not answer. Fail-closed: the call did not run. Distinct from a 403, which is a decision that was taken.

Response 200

FieldTypeRequiredDescription
datano
durationnumberyes
headersobjectyes
proxy_call_idstringyespx_-prefixed id of the logged call.
statusintegeryesThe UPSTREAM status code, not this call's.

Example response

{
  "status": 0,
  "headers": {},
  "duration": 0,
  "proxy_call_id": "proxycall_0000000000000000"
}

Example request

curl -X POST https://api.codespar.dev/v1/sessions/{id}/proxy_execute \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "server": "string",
       "endpoint": "https://example.com/hook",
       "method": "GET",
       "params": {},
       "headers": {},
       "estimatedCost": 0
     }'

POST /v1/sessions/{id}/send

Drive a model loop that may call tools

Path parameters

NameTypeRequiredDescription
idstringyes

Request body

FieldTypeRequiredDescription
messagestringyes

Responses

StatusBodyDescription
200objectOK
400objectBad Request — the body or query did not match the schema.
403objectForbidden — the org's monthly tool-call allowance is spent.
404objectNot Found
409objectConflict — the session is not active, so it dispatches nothing.
500objectInternal Server Error — the loop failed mid-flight. Carries the work that already completed, in the same fields as the 200.
503objectService Unavailable — this deployment has no model credential configured.

Response 200

FieldTypeRequiredDescription
abortedtrueno
iterationsintegeryes
messagestringyesThe model's last text turn. Empty when it ended on a tool call.
tool_callsarray of objectyes

Example response

{
  "message": "string",
  "tool_calls": [
    {
      "id": "obj_0000000000000000",
      "tool_name": "Example",
      "server_id": "srv_0000000000000000",
      "status": "success",
      "duration_ms": 0
    }
  ],
  "iterations": 0,
  "aborted": true
}

Example request

curl -X POST https://api.codespar.dev/v1/sessions/{id}/send \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "message": "string"
     }'

GET /v1/sessions/{id}/tool-calls

List one session's tool calls

Path parameters

NameTypeRequiredDescription
idstringyes

Query parameters

NameTypeRequiredDescription
limitintegerno

Responses

StatusBodyDescription
200objectOK
400objectBad Request — the body or query did not match the schema.
404objectNot Found

Response 200

FieldTypeRequiredDescription
tool_callsarray of ToolCallyes

Example response

{
  "tool_calls": [
    {
      "id": "tc_0000000000000000",
      "session_id": "ses_0000000000000000",
      "server_id": "srv_0000000000000000",
      "tool_name": "Example",
      "status": "running",
      "called_at": "2026-01-15T12:00:00.000Z"
    }
  ]
}

Example request

curl -X GET https://api.codespar.dev/v1/sessions/{id}/tool-calls \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/sessions/{id}/tool-calls

Record a tool call the client executed

Path parameters

NameTypeRequiredDescription
idstringyes

Request body

FieldTypeRequiredDescription
duration_msintegerno
error_codestringno
inputno
outputno
server_idstringyes
status"running" | "success" | "error"no
tool_namestringyes

Responses

StatusBodyDescription
201ToolCallOK
400objectBad Request — the body or query did not match the schema.
404objectNot Found
409objectOK

Response 201

FieldTypeRequiredDescription
called_atstring (date-time)yes
duration_msinteger,nullyes
error_codestring,nullyes
failover_trailno
idstringyestc_-prefixed: the bigserial with a tc_ prefix prepended
inputno
outputno
routingno
server_idstringyes
session_idstringyes
status"running" | "success" | "error"yes
tool_namestringyes

Example response

{
  "id": "tc_0000000000000000",
  "session_id": "ses_0000000000000000",
  "server_id": "srv_0000000000000000",
  "tool_name": "Example",
  "status": "running",
  "called_at": "2026-01-15T12:00:00.000Z"
}

Example request

curl -X POST https://api.codespar.dev/v1/sessions/{id}/tool-calls \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "server_id": "srv_0000000000000000",
       "tool_name": "Example",
       "status": "running",
       "duration_ms": 0,
       "error_code": "string"
     }'

PATCH /v1/sessions/{id}/tool-calls/{tc_id}

Finalize a recorded tool call

Path parameters

NameTypeRequiredDescription
idstringyes
tc_idstringyestc_-prefixed

Request body

FieldTypeRequiredDescription
duration_msintegerno
error_codestring,nullno
outputno
status"success" | "error"no

Responses

StatusBodyDescription
200ToolCallOK
400objectBad Request — the body or query did not match the schema.
404objectNot Found

Response 200

FieldTypeRequiredDescription
called_atstring (date-time)yes
duration_msinteger,nullyes
error_codestring,nullyes
failover_trailno
idstringyestc_-prefixed: the bigserial with a tc_ prefix prepended
inputno
outputno
routingno
server_idstringyes
session_idstringyes
status"running" | "success" | "error"yes
tool_namestringyes

Example response

{
  "id": "tc_0000000000000000",
  "session_id": "ses_0000000000000000",
  "server_id": "srv_0000000000000000",
  "tool_name": "Example",
  "status": "running",
  "called_at": "2026-01-15T12:00:00.000Z"
}

Example request

curl -X PATCH https://api.codespar.dev/v1/sessions/{id}/tool-calls/{tc_id} \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "status": "success",
       "duration_ms": 0
     }'

On this page

SessionsProject scopingPOST /v1/sessionsRequest bodycurl exampleResponse -- 201 CreatedSDK equivalentGET /v1/sessionsQuery parameterscurl exampleResponse -- 200 OKGET /v1/sessions/:idcurl exampleResponse -- 200 OKDELETE /v1/sessions/:idcurl exampleResponse -- 200 OKSDK equivalentPOST /v1/sessions/:id/executeRequest bodycurl exampleResponse -- 200 OKSDK equivalentPOST /v1/sessions/:id/sendRequest bodycurl exampleResponse -- 200 OKStreaming variantSDK equivalentGET /v1/sessions/:id/connectionscurl exampleResponse -- 200 OKSDK equivalentPOST /v1/sessions/:id/tool-callsRequest bodycurl exampleResponse -- 201 CreatedGET /v1/sessions/:id/tool-callsQuery parameterscurl exampleResponse -- 200 OKPATCH /v1/sessions/:id/tool-calls/:tc_idRequest bodycurl exampleResponse -- 200 OKGET /v1/healthcurl exampleResponse -- 200 OKGET /healthcurl exampleResponse -- 200 OKAsync settlementCorrelation chainWhere the idempotency key lands, per providerPolling or streamingStreaming statusEvent shapeHeartbeatsCallbacks and cancellationGET /v1/tool-calls/:id/payment-statuscurl exampleResponse -- 200 OK (settled)Response -- 200 OK (pending)SDK equivalentGET /v1/tool-calls/:id/payment-status/streamcurl exampleStream outputSDK equivalentGET /v1/tool-calls/:id/verification-statuscurl exampleResponse -- 200 OKSDK equivalentGET /v1/tool-calls/:id/verification-status/streamcurl exampleSDK equivalentGET /v1/meta-tools/statsRequestResponse -- 200 OKGET /v1/meta-tools/stats/hourlyQuery parametersRequestResponse -- 200 OKPOST /v1/connections/hmac-validateRequest bodycurl exampleResponse -- 200 OKResponse -- 200 OK (invalid)Error responsesRate limit headersNext stepsEvery operation, from the specGET /v1/sessionsPOST /v1/sessionsGET /v1/sessions/{id}DELETE /v1/sessions/{id}GET /v1/sessions/{id}/connectionsPOST /v1/sessions/{id}/executeGET /v1/sessions/{id}/mocksPOST /v1/sessions/{id}/proxy_executePOST /v1/sessions/{id}/sendGET /v1/sessions/{id}/tool-callsPOST /v1/sessions/{id}/tool-callsPATCH /v1/sessions/{id}/tool-calls/{tc_id}
Sessions | CodeSpar