Overview
Base URL, authentication, errors and conventions — plus what this document does not describe.
API reference
The CodeSpar API is REST over HTTPS: resource-oriented paths, JSON bodies, conventional status codes. Every operation on these pages is generated from the OpenAPI document served at https://api.codespar.dev/openapi.json — the same one a generated client reads — and every one of them can be run from its own page with your key.
Base URL
There is one. The key prefix picks the environment, not the host: csk_test_ and csk_live_ reach this same URL and act on different data. A call that seems to return nothing is often a live key reading a sandbox project, or the reverse.
Authentication
Every operation takes a bearer token.
GET /v1/whoami is the right first call, and the right first thing to run when something is not working: it answers whether the key is valid, which organization and project it is bound to, which environment it acts in, and which scopes it holds — four questions at once. An OAuth 2.1 access token from the flow advertised at /.well-known/oauth-authorization-server is accepted on the same header.
Errors
A refusal is explicit and carries a code. A call that would exceed a mandate cap fails rather than partially succeeding, and the failure names the cap.
Every response carries X-Request-Id, including failures. It is the single most useful thing to quote when you ask for help: it finds your exact call instead of a description of it.
The body of a refusal
⚠️ Two shapes coexist in this API, and a client that parses one as the other reads undefined where it expected a string. The newer routes answer:
{
"error": {
"code": "not_found",
"message": "paywall not found"
},
"request_id": "req_01J8…"
}Older routes answer a bare { "error": "not_found" }, sometimes with an issues array alongside it when the refusal is a validation failure. Each operation's page shows the shape that operation actually returns — read it there rather than assuming.
Conventions
Amounts are in minor units. 1990 is R$ 19,90. The crypto rails are the exception and take major units; each says so on its own page.
Idempotency is yours to pass. Where an operation moves money it takes an idempotency_key, and reusing the same key verbatim on a retry is what keeps a retry from becoming a second payment. A new key for the same operation is a new operation.
Asynchrony is normal on the money rails. A Pix cash-out answers PROCESSING when it was accepted and is settling; a cobrança com vencimento answers with no document until the clearing house registers it. Neither is a failure. Subscribe a trigger, or poll the operation's own status call.
A resource that is not yours is a 404, never a 403. Existence is not probeable across the tenant boundary.
How to read an operation
Under each operation's heading there is a bar: the verb in its own colour, then the full URL, with the {parameters} you have to fill in picked out. Marks can appear below it, and they do not all come from the same place, which is the part worth knowing.
Deprecated and No credential are read straight from the published document: the first is its own deprecated flag, the second is an operation that declares no security requirement at all.
Moves money and Can move money are not in the document. There is no field for them: no tag, no scope, nothing a generator can read as a fact. They come from a rule in scripts/api-reference/generate.mjs, and the rule has two halves. The mechanical half reads the document and flags a write as suspect when its body carries an amount field, its description uses a money verb, its path names a movement, or it lives under the wallet or facilitator tree. Suspicion on its own marks nothing: an amount field also matches operations that record a negotiated price or store a cap, and a money verb matches prose. The other half is a verdict per suspect, written by a person and justified by a sentence copied from that operation's own description; the generator refuses to run while any suspect lacks one, and refuses again if the sentence stops appearing in the description, so a verdict cannot outlive the text it rests on. Today 5 of the 213 operations carry Moves money and 3 carry Can move money, the second being operations that run whatever tool the caller names, which may be a paid one. Read the sentence under the mark: it is the evidence, not a summary.
The example is the same request twice, in curl and in TypeScript. A third tab appears only where the published client has a method for that route, which is a handful of session operations and no more: @codespar/sdk is a session client, not a REST client, so an SDK tab on the rest would be a method that does not exist.
Client libraries
The examples here are curl, and you do not have to write HTTP: the SDK is the TypeScript client, the CLI drives the same operations from a terminal, and the hosted MCP server exposes the meta-tools to an agent with no HTTP client at all.
Where the money verbs are, and they are not here
Charging someone, refunding, issuing or paying a boleto, invoicing and checkout are not REST routes. Measured against this document: /v1/charges, /v1/refunds, /v1/boletos, /v1/invoices and /v1/checkout do not exist, and neither does any route under another name that does those jobs.
They exist as meta-tool actions instead — codespar_charge, codespar_invoice, codespar_checkout, and codespar_pay with method=boleto or action=pix_devolution — reachable over MCP or through the SDK. A reader who comes here looking for how to take a payment will not find it on these pages, and that is a gap in the API rather than a gap in this reference. Until it closes, the meta-tools are where the money verbs live, and their schemas are published at https://api.codespar.dev/v1/meta-tools.json without a credential.
What IS here is the platform surface: consumers, wallets, mandates, connections, projects, sessions, triggers, DDA, Pix keys, receipts and the rest — the things you configure and read, as opposed to the things that move money.
What this document does not describe
These pages cover all 213 operations the published document describes, across 54 resource groups. They are complete with respect to that document and say nothing about surfaces it does not describe yet — silently, because a generator cannot report what its input never mentioned. When you cannot find an operation here, the right conclusion is "the spec does not describe it yet", not "it does not exist".
Every example on these pages is synthesised from the schema, not captured from a real call: the published document carries no example values. The shapes are right; the values are placeholders.