Capxul Docs
Concepts

Mental model

How to think about the Capxul SDK — a method-based client over a money substrate, a deliberately narrow public surface, and an explicit result boundary.

Capxul lets an application work with identity, accounts, organizations, and money movement without building on the machinery underneath — auth provider calls, backend functions, settlement execution, transaction evidence. Your app says what should happen; Capxul makes it happen and returns durable records your app can render.

The whole SDK follows from one sentence:

Your app owns screens, routing, product intent, and presentation state. Capxul owns identity, account readiness, organization authority, money movement, and the substrate that makes those things durable.

Application code
  routes, forms, dashboards, product decisions
  calls SDK hooks or client methods

Capxul SDK surface
  session, profile, account lifecycle, actor, payment, request, org
  stable product records and mutation results

Capxul control plane
  auth, identity persistence, account setup, membership, policy checks
  money ledger, payment documents, reconciliation

Substrate (hidden from app code)
  settlement execution, account infrastructure, transaction evidence

If a concept affects what the user experiences, it appears as a product object, a lifecycle status, or a hook result. If a concept only explains how Capxul implemented that experience, it stays out of app code.

A method-based client

The core of the SDK is CapxulClient, organized as method bundles:

client.auth.signIn({ email });
client.account.getLifecycle();
client.payments.pay({ to, amount });
client.paymentRequests.create(input);
client.org(orgId).members();

Each bundle is a domain — auth, account, payments, requests, organizations — and each method expresses product intent ("pay this person", "complete onboarding") rather than substrate mechanics. The methods return product records: a Payment with a status, an amount, and documents — not a transaction receipt.

The client/hooks split

There are two entry points, and they are the same client underneath:

  • @capxul/sdk — the imperative client, for scripts, servers, CLIs, agents, and anything not naturally React-rendered. You create it with createCapxulClient and call methods directly.
  • @capxul/sdk-react — React bindings. CapxulProvider owns client creation, bootstrap state, and the TanStack Query cache; the hooks are thin query/mutation bindings over the client methods.

The hooks do not add capability — they add React ergonomics. A query hook like useCapxulAccountBalance hides the cache key, waits for bootstrap, unwraps the result, and re-fetches when a mutation invalidates it. A mutation hook like useCapxulPay surfaces isPending and error and invalidates the money state it changed. The hooks own reactivity; you still own the UI.

The surface is intentionally narrow

Creating a client takes a publishable key — and almost nothing else:

const result = await createCapxulClient({
  publishableKey: process.env.CAPXUL_PUBLISHABLE_KEY!,
  requirement: "counterfactual",
});

The publishable key identifies your registered application; from it the SDK resolves everything else — endpoints, runtime detection, timeouts, caching defaults. The only other public inputs are requirement (how much account setup your app needs — see the account lane) and an optional signer for transaction-capable accounts.

This narrowness is deliberate, and it is worth understanding why:

  • The hidden layers stay changeable. Capxul has already restructured its internal setup steps without breaking apps, because no app could reach them.
  • App code cannot drift into the substrate. If transports, endpoints, and adapters were public options, product code would slowly take dependencies on machinery that was never a contract.
  • The vocabulary stays money-shaped. A narrow surface is how the SDK keeps custody concepts from leaking into your codebase.

The trade-off is real: you cannot tune transport behavior, swap endpoints, or intercept setup steps from app code. Internal seams exist for Capxul's own tests and hermetic harnesses, but they are not the app surface — if you feel you need one for a product screen, look for the public record that represents what you actually want to render.

Bootstrap is not login

CapxulProvider (or createCapxulClient) starts by bootstrapping the application: validating the publishable key and resolving runtime configuration. That says nothing about a user. Keep the four readiness states separate:

StateRead it withMeaning
Bootstrap readyuseCapxul()The SDK client is ready for this app.
Signed inuseCapxulSession()There is an authenticated user session.
Profile availableuseCapxulProfile()Capxul has an identity record for the user.
Account readyuseCapxulAccountLifecycle()The account requirement the app chose is satisfied.

Route guards usually want the session. Money surfaces usually want the account lifecycle. Treating "signed in" as "ready to transact" is the most common integration mistake; the states exist separately because the work between them is real.

Results, not thrown surprises

Every public client method returns Promise<CapxulResult<T>>:

type CapxulResult<T> = { ok: true; value: T } | { ok: false; error: CapxulError };
const paid = await client.payments.pay(input);

if (!paid.ok) {
  report(paid.error.message);
  return;
}

renderPayment(paid.value);

The success/error boundary is explicit and typed — you never catch unknown thrown values from product methods. React hooks unwrap this for you: failures surface as a CapxulError on the hook's error field, in normal TanStack Query fashion.

Recovery follows the same layering. Do not rebuild the client after an error; use the retry point that matches where the failure lives — useCapxul().retry() for bootstrap failures, the account lifecycle's retry() for setup failures, and the mutation's own retry for form-level failures.

The rule of thumb

When you are unsure whether something belongs in your app state, ask which side of the split it is on. Selected route, form input, table filters, a selected orgId or paymentId — yours. Session, profile, lifecycle, balances, payments, members — Capxul's, read through hooks or client methods, never cached in local copies the SDK is already maintaining and invalidating.

The rest of the concepts section unpacks the two vocabularies this model rests on: money & accounts for what moves, and identity & organizations for who moves it.

On this page