Skip to main content
Managed wallets are the primary Cesto integration: for each of your users, Cesto provisions a Solana wallet backed by Privy and signs transactions on its side. Your backend never touches a private key, never runs a signing callback, and never builds a browser signing flow — you call users.create once per user, fund the wallet, and open / close / rebalance by user reference. This is the path to pick when your end users only have an EVM wallet (e.g. on Base) and you don’t want to run Solana wallet infrastructure. It is also the recommended path in every how-to on this site — the “Managed” tab comes first wherever both flows are shown.

Prerequisites

  • A write-scoped API key. Every call on this page except users.get is a write route — read-only keys get a 403 (PermissionDeniedError). Keys are created and scoped in the Cesto dashboard or by the Cesto team — see Authentication.
  • A provisioning quota. Each write key has a managed-user quota (contact the Cesto team to set or raise it). When it’s full, users.create fails with a 403, code PROVISIONING_QUOTA_EXCEEDED.
  • Server-side execution. Managed calls run from your backend — the API key must never ship to a browser or mobile client. Read it from the environment (process.env.CESTO_API_KEY), never hardcode it, and keep it out of version control.
  • USDC on Base in the user’s EVM wallet (or another supported funding route) — this is what gets bridged in and invested.
These examples move real mainnet funds. Bridging and investing run on Base and Solana mainnet with real USDC. Test with small amounts first.

Provisioning users

users.create idempotently provisions a Cesto-managed Privy Solana wallet for a user, keyed to their EVM wallet address:
  • Idempotent — calling create again for the same EVM wallet returns the same record with created: false. It’s safe to call on every login.
  • One wallet per (partner, EVM wallet) — the mapping is fully isolated per API key: another partner provisioning the same EVM address gets a different, unrelated user.
  • Quota — each write key has a provisioning quota. When it’s full, create fails with a 403 (code PROVISIONING_QUOTA_EXCEEDED) — talk to the Cesto team to raise it.
  • Rate limitusers.create is limited to 10 requests/minute per key.
To look a user up later, users.get resolves by EVM wallet address:
users.get works with a read-scoped key. A 404 means this EVM wallet was never provisioned under your key — even if another partner provisioned it, it isn’t yours.

Endpoint reference

Funding the wallet

Users fund their managed wallet by bridging USDC from their EVM wallet with the existing bridge flow (Base → Solana, Circle CCTP). Two things matter:
  • recipient is the provisioned solanaAddress.
  • sourceAddress is the user’s EVM wallet — the user signs the burn on Base, as usual.
Funding is the one step that looks the same in both models: the funds come from the user’s EVM wallet, so the user always signs the EVM-side burn. The managed part is only the destination — the provisioned solanaAddress.
When the transfer completes, invest what arriveddone.netOut — not the burn amount (fast mode deducts its fee at mint).
Full bridge mechanics, modes, and errors are in Bridging (CCTP).

Opening, closing, rebalancing

Managed positions are custodial: Cesto signs for the provisioned wallet server-side, so no user signature, signTransactions callback, or split flow is needed. Each call returns an { executionId } and the execution runs in the background. All three are write routes.
start is the single server-signed entry point, and it covers two kinds of user. Managed users are the case with no consent field: Cesto holds their key, so there is nothing for them to sign and your API key is the sole authority. A Cesto account holder — someone with their own wallet — must instead approve each action by signing a challenge, passed as consent. See Existing Cesto users.
The user field accepts any of your user’s identifiers:
  • the externalUserId you passed at provisioning,
  • the user’s EVM wallet address, or
  • the provisioned Solana address.
As with the client-signed flow, close sells the user’s full holding of the basket (no amount, no partial close) and rebalance migrates the position to the basket’s latest version. amount on open is a bigint in input-token base units.Full reference: Opening, closing, rebalancing on this page — the rest of this section applies to the managed flow.
Managed executions are scoped per API key — one partner never sees another’s users or executions. A user that doesn’t resolve to one of your provisioned users fails with a 404 (code MANAGED_USER_NOT_FOUND).

Waiting for the result

The *AndWait convenience variants kick off the operation and then poll the existing execution-status endpoint until a terminal status — COMPLETED, PARTIALLY_COMPLETED, or FAILED:
close.startAndWait and rebalance.startAndWait take the same params as their start counterparts. To poll an execution you kicked off with the plain variants, use the shared positions.getExecution / positions.waitForExecution with the returned executionId — polling is identical in both models.
Partial completion is real, exactly as in the client-signed flow: a multi-token open is several independent transactions with no atomicity across them. Check result.status and result.transactions before assuming the full amount landed.

Withdrawing

Withdrawal is the mirror image of funding — and needs no user signature at all in the managed model:
1

Close the position

close.start (or close.startAndWait) sells the full holding back to USDC on the managed wallet.
2

Bridge back to EVM

Use bridge with sourceChain: 'solana', destChain: 'base', the managed wallet as sourceAddress, and the user’s EVM wallet as recipient.
For a managed Solana source wallet, Cesto signs and lands the burn itself (sponsor pays gas and the CCTP message-account rent — managed wallets hold no SOL): initiate returns { status: 'BURN_SUBMITTED', burnTxHash, burn: null }, so skip submitBurn and go straight to waitForTransfer.

Errors

See Errors & Retries for the typed error hierarchy and retry behavior.

Rate limits

Per API key: Exceeding a limit returns 429 (RateLimitError) with a retryAfter hint. Because users.create is idempotent, call it on login rather than caching a lookup table of your own — 10/minute is ample for user-driven provisioning.

Security notes

  • Server-side only. Every managed call carries your API key; never expose it to a browser, mobile app, or logs. Load it from the environment (process.env.CESTO_API_KEY), as in every example on this page.
  • Write scope gates every mutation. Provisioning, opening, closing, rebalancing, and bridging all require a write-scoped key. Keep a separate read-scoped key for status reads and dashboards if you want least-privilege separation.
  • No keys to leak on your side. The managed wallet’s key material lives in Cesto’s Privy custody and never crosses your infrastructure — there is nothing in your stack to exfiltrate. Treat the API key itself as the sensitive secret.
  • Per-key isolation. Users, executions, and bridge transfers are visible only to the API key that created them.

End-to-end example

Provision a user, bridge USDC in from their EVM wallet, open a position, then close it and bridge back out — no key handling anywhere on your side:
This flow runs against Base and Solana mainnet and moves real USDC. Run it with small amounts until you’re confident in the integration.