Skip to content

feat(treasury): CrossmintTreasury server SDK + client read service#1845

Draft
AngelPaella wants to merge 2 commits into
mainfrom
angel/treasury-sdk-surface
Draft

feat(treasury): CrossmintTreasury server SDK + client read service#1845
AngelPaella wants to merge 2 commits into
mainfrom
angel/treasury-sdk-surface

Conversation

@AngelPaella
Copy link
Copy Markdown

Summary

Public SDK surface for the B2B Treasury API (/api/2026-05-11/treasury/*). Companion to the crossbit-main backend PR.

  • packages/server/src/treasury/CrossmintTreasury.ts (commit 88b8f56b): server-side SDK class with full write + read surface. sk_* keys only — apiKeyExpectations.usageOrigin: "server" rejects client keys at the API client level. Auto-Idempotency-Key with caller override; typed CrossmintTreasuryError with stable code field. Methods: createPayout / getPayout, createOfframp / getOfframp, registerHifiOfframpAccount, registerOpenPaydBeneficiary, listAccounts, getBalances, listTransactions. 11 vitest tests.

  • packages/client/base/src/services/treasury/ (commit faff0086): factory-based read-only client surface for browser / RN flows holding a ck_* key. Methods: getPayout, getOfframp, listTransactions, getBalances, listAccounts. Writes intentionally NOT exposed — compliance + idempotency stay server-side.

  • packages/server/src/treasury/errors.ts (commit faff0086): refreshed JSDoc with the error codes added in crossbit-main Phase 9.2-apps + 11.3 (treasury.offramp.currency_unsupported, treasury.account.not_provisioned, treasury.account.misconfigured, treasury.region.*, treasury.route.unsupported, treasury.settlement_chain.unresolved). Removed treasury.offramp.eu_workflow_pending — no longer thrown since the EU saga went live in 9.2-apps.

API version pinning

TREASURY_API_VERSION is pinned to 2026-05-11 in both packages. When the backend bumps to a later dated version, add a new class (e.g. CrossmintTreasury2027) rather than mutating the existing one — consumers pin SDK versions and a wire-version bump is a breaking change.

Not in scope

  • EU offramp Model A two-call wrapper (createOfframpWithSignerPrompt) — backend currently kicks off the workflow on POST without a separate /authorize endpoint per the 9.2-apps simplification. If Model A becomes load-bearing in product, expose the wrapper then.
  • Treasury write methods on the client SDK — intentional; writes belong on the server boundary.

Test plan

  • pnpm --filter @crossmint/server-sdk test:vitest green
  • pnpm --filter @crossmint/client-sdk-base build clean (no type errors)
  • Hand-typed Node script calling createPayout against staging returns 200 with the typed response shape
  • Client SDK getOfframp polls correctly from a browser with a ck_* key

calderaro added 2 commits May 13, 2026 09:06
Region-agnostic server-side SDK for the 2026-05-11/treasury/* API. Mirrors
the CrossmintAuth shape: from(crossmint) factory, apiClient-driven, typed
errors. Server-key only (rejects ck_* at construction).

Methods:
- createPayout(req, { idempotencyKey? }) / getPayout(id)
- createOfframp(req, { idempotencyKey? }) / getOfframp(id)
- registerHifiOfframpAccount(req)        — US rail
- registerOpenPaydBeneficiary(req)       — EU rail
- listAccounts() / getBalances() / listTransactions({ kind?, limit?, cursor? })

Highlights:
- Idempotency-Key built in. Auto-gen UUIDv4 per write; caller can override
  for derived-key lineage.
- Public types defined locally in treasury/types.ts (no dep on the backend
  monorepo's @crossmint/products-payments-types workspace package).
- CrossmintTreasuryError carries stable `code` field — match on code, not
  message. Common codes documented inline.
- TREASURY_API_VERSION = "2026-05-11" pinned. Future contract bumps land
  as parallel class surfaces, not mutations.

Tests: 11 new in CrossmintTreasury.test.ts (Idempotency-Key header,
URL-encoding, query-string building, error-shape decoding, raw-payload
preservation on typed errors). 47 total @crossmint/server-sdk tests
green (was 36, +11).
…ase 10.2 — SDK delta)

Companion to the server-sdk Treasury surface (88b8f56). Two pieces:

(1) New `createCrossmintTreasuryClient` factory in client-sdk-base.
    Read-only methods (getPayout, getOfframp, listTransactions,
    getBalances, listAccounts) for browser / RN flows that hold a `ck_*`
    client key and just need to poll status. Writes stay server-side
    where compliance + idempotency belong. Follows the existing
    factory-pattern of paymentMethodManagementService — consumers pass a
    pre-constructed CrossmintApiClient, the factory returns the typed
    surface.

    Types are loose `unknown` projections here — the client polling
    facade returns the server-shape directly; consumers typically already
    have the typed shapes from @crossmint/server-sdk/treasury or their
    own backend response types. Keeping types minimal avoids a dep edge
    from client-base to server-sdk.

(2) Refresh server errors.ts with the codes added in crossbit-main
    Phase 9.2-apps (`1edfd638dc`) and 11.3 (`8ccee1c7f1`):
      - treasury.offramp.currency_unsupported (400)
      - treasury.account.not_provisioned (400, EU path)
      - treasury.account.misconfigured (400, missing env)
      - treasury.account.unavailable (500)
      - treasury.region.* / treasury.route.unsupported (400/500)
      - treasury.settlement_chain.unresolved (400)

    Documented that treasury.offramp.eu_workflow_pending was removed in
    9.2-apps — the EU saga is now live and returns a real `pending`
    envelope.

Not in scope (deferred):
  - EU offramp Model A two-call wrapper (createOfframpWithSignerPrompt) —
    backend currently kicks off the workflow on POST without a separate
    /authorize endpoint, per the 9.2-apps simplification. If Model A
    surfaces as load-bearing later, expose the wrapper then.
  - Treasury write methods on the client SDK — intentional; writes belong
    on the server boundary.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 15, 2026

🦋 Changeset detected

Latest commit: faff008

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@crossmint/server-sdk Minor
@crossmint/auth-ssr-nextjs-demo Patch
crossmint-auth-node Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants