Quickstart
Install @cavos/kit, connect to one or more chains, and execute your first sponsored transaction.
The onboarding contract is shared across every Cavos adapter: authenticate,
connect, then execute. Connect derives addresses and checks deployment status
but never deploys. The first execute triggers deployment atomically with
the user's operation.
1. Install
npm install @cavos/kitCreate an app in the Cavos dashboard and copy its App ID. Starknet sponsorship also requires a paymaster API key. The current web SDK receives that value in browser code, so it must be treated as a client-visible, app-scoped sponsorship credential, never as an operator or treasury secret. Before production, bind and limit it by app, environment, origin, rate, and spend in the sponsorship service.
2. Connect
Connect derives the address for every configured chain and checks whether the
account exists on-chain. It never deploys. Deployment happens lazily on the
first execute call.
This Solana example needs only the public App ID in the browser:
import { Cavos } from "@cavos/kit";
const session = await Cavos.connect({
chains: ["solana"],
defaultChain: "solana",
network: "testnet",
appSalt: "my-app",
identity: {
userId: user.id, // stable, immutable identifier
email: user.email,
},
appId: process.env.NEXT_PUBLIC_CAVOS_APP_ID,
});
console.log(session.address); // the address for the default chain
console.log(session.status); // "undeployed" | "ready" | "needs-device-approval"The returned session is the default chain's wallet augmented with multi-chain
methods. session.wallet("solana") returns the Solana wallet;
session.chainStatus("solana") returns its status.
Status values
| Status | Meaning | Can execute? |
|---|---|---|
undeployed | Address derived but no on-chain account yet. | Yes — first execute deploys + runs atomically. |
ready | Account deployed and this device is authorized. | Yes |
needs-device-approval | Account deployed but this device is not a signer. | No — route to device approval. |
Lazy deploy: An undeployed wallet can sign messages (signMessage) and
execute. The first execute call deploys the account and runs the user's
operation in a single sponsored transaction. No separate deploy step is needed.
3. Execute
Narrow on wallet.chain so TypeScript exposes the correct native method. Both
undeployed and ready wallets can execute.
const wallet = session.wallet("solana");
// Only needs-device-approval must be handled differently
if (wallet.status === "needs-device-approval") {
throw new Error("This device must be approved first");
}
if (wallet.chain === "starknet") {
const { transactionHash } = await wallet.execute(calls);
} else if (wallet.chain === "solana") {
const signature = await wallet.execute(1_000_000n, solanaRecipient); // lamports
} else if (wallet.chain === "stellar") {
const hash = await wallet.execute(1_000_000n, stellarRecipient); // stroops
}When the account is undeployed, execute deploys it first, then runs the
operation — atomically, in a single sponsored transaction. After the first
execute, status becomes ready.
For arbitrary execution, Starknet accepts multicalls, Solana exposes
executeInstructions, and Stellar exposes invokeContract. Each path has
adapter-specific validation and sponsorship rules.
4. Configure the selected adapter
| Adapter | Required configuration | Sponsored execution |
|---|---|---|
| Starknet | App ID, network, app salt, identity, paymasterApiKey | Paymaster sponsors deploy and execute. |
| Solana | App ID, network, app salt, identity | Hosted relayer becomes fee payer; arbitrary programs are allowlisted per app. |
| Stellar | App ID, network, app salt, identity | Hosted relayer can sponsor reserves and fee-bump submission. |
Use the dedicated Starknet, Solana, or Stellar guide for production configuration.
5. Handle device approval
status === "needs-device-approval" means the identity already owns a wallet
but this device is not enrolled. Do not create a second wallet. Route the user
through Passkeys (recommended), Multi-device,
or the adapter's Recovery path.
Passkeys and recovery share a product goal across chains, but their cryptographic implementation differs. Use the high-level wallet methods and follow the selected adapter's capability notes.
More than one chain
Connect once, access every configured chain. The session provides wallets for all chains without re-authenticating:
const session = await Cavos.connect({
chains: ["solana", "stellar", "starknet"],
defaultChain: "solana",
network: "testnet",
appSalt: "my-app",
identity,
appId: process.env.NEXT_PUBLIC_CAVOS_APP_ID,
paymasterApiKey: process.env.NEXT_PUBLIC_CAVOS_PAYMASTER_API_KEY, // Starknet only
});
// Access any chain's wallet
const solana = session.wallet("solana");
const stellar = session.wallet("stellar");
const starknet = session.wallet("starknet");
// Check status per chain
console.log(session.chainStatus("solana")); // "undeployed" | "ready" | "needs-device-approval"
console.log(session.chainStatus("stellar"));
console.log(session.chainAddress("stellar")); // G… address
// Execute on Stellar (works even if undeployed — first execute creates the account)
if (stellar.chain === "stellar" && stellar.status !== "needs-device-approval") {
await stellar.execute(10_000_000n, "GDEST...");
}Each chain has its own address, derived from the same identity. Deploy happens independently per chain on first execute. One login, multiple wallets, no re-authentication.
React
For UI applications, use the bindings from @cavos/kit/react:
import { CavosProvider } from "@cavos/kit/react";
export function Providers({ children }) {
return (
<CavosProvider
config={{
chains: ["solana", "stellar"],
defaultChain: "solana",
network: "testnet",
appSalt: "my-app",
appId: process.env.NEXT_PUBLIC_CAVOS_APP_ID,
}}
modal={{ appName: "My App" }}
>
{children}
</CavosProvider>
);
}The provider gives you setChain(chain) to switch the active chain without
re-mounting or re-authenticating. See React for the full guide.
Continue with React, React Native, or the full API reference.
If something does not behave as described here, Troubleshooting lists the symptoms integrators hit most and what actually causes them.