Headless SDK
@gizmolab/depositos ships in two flavours:
- Batteries-included — drop in
<DepositOSWidget />, theme it with config, done. - Headless — import composable hooks + primitives from
@gizmolab/depositos/headlessand build your own UI and flow on top of the depositOS engine.
Use headless when you want full control of the layout/UX (custom wallet picker, custom token list, embed the flow inside your own screens) while reusing our quoting, execution, balance, and analytics plumbing.
npm install @gizmolab/depositos
Providers
Headless needs two providers: the depositOS wallet provider (wallet + email login)
wrapping the depositOS DepositOSProvider (deposit state + config). Both come from
@gizmolab/depositos — no third-party imports.
import {
DepositOSWalletProvider,
EthereumWalletConnectors,
SolanaWalletConnectors,
DepositOSProvider,
} from "@gizmolab/depositos";
const config = {
destChain: 42161,
destToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
destAddress: "0xYourTreasury",
apiKey: "dos_live_…", // from the depositOS portal — attributes volume/txns to your app
};
export function Providers({ children }) {
return (
<DepositOSWalletProvider
settings={{
environmentId: process.env.NEXT_PUBLIC_DEPOSITOS_WALLET_ENV_ID!,
walletConnectors: [EthereumWalletConnectors, SolanaWalletConnectors],
}}
>
<DepositOSProvider config={config}>{children}</DepositOSProvider>
</DepositOSWalletProvider>
);
}
Hooks
| Hook | Returns |
| --- | --- |
| useDepositOSState() | { config, state, dispatch, reset } — the deposit state machine. |
| useWalletTokens() | { tokens, loading, error, address, refetch } — tokens the connected wallet actually holds (non-zero, USD-sorted). |
| useQuote() | Auto-fetches a route when source token + amount are set; writes to state. |
| useExecution() | { runExecute } — approve + bridge/swap the current quote. |
| useWalletSync() | Keeps the connected wallet in sync with deposit state. |
| useDepositAnywhere(config, onSuccess?, resume?, onWithdrawReady?) | "Deposit from anywhere" flow. Returns the user's persistent deposit address (see config.userId), the chain/token pickers, and live status. |
| usePrivateSwap(config) | Private-mode swap flow. |
Data primitives (framework-agnostic)
fetchWalletTokens, fetchChains, fetchTokens, fetchQuote, quoteToRoute,
executeRoute, sendEvent,
setEventsApiKey, setWalletEnvironmentId, address helpers (isEVMAddress,
isSolanaAddress, maskAddress), and SOLANA_CHAIN_ID / isSolanaChainId.
UI primitives
Compose your own screens with WalletFlow, ChainTokenSelector, TokenSelector,
AmountInput, and WalletConnect, or ignore them and build everything yourself.
Full example — a minimal custom flow
Connect wallet → list held tokens → pick one → enter amount → deposit. No prebuilt widget; just hooks.
"use client";
import { useState } from "react";
import {
useWalletTokens,
useQuote,
useExecution,
useWalletSync,
useDepositOSState,
type WalletToken,
} from "@gizmolab/depositos/headless";
export function CustomDepositFlow() {
useWalletSync(); // sync connected wallet → deposit state
useQuote(); // auto-quote when source token + amount are set
const { runExecute } = useExecution();
const { state, dispatch } = useDepositOSState();
const { tokens, loading } = useWalletTokens();
const [picked, setPicked] = useState<WalletToken | null>(null);
// 1. Not connected → render your own connect UI (or the exported WalletConnect)
if (!state /* replace with your own connected check */ && false) return null;
// 2. Pick a token the wallet already holds
if (!picked) {
if (loading) return <p>Loading balances…</p>;
return (
<ul>
{tokens.map((t) => (
<li key={`${t.chainId}:${t.address}`}>
<button
onClick={() => {
setPicked(t);
dispatch({ type: "SET_SOURCE_CHAIN", payload: t.chainId });
dispatch({
type: "SET_SOURCE_TOKEN",
payload: { address: t.address, decimals: t.decimals },
});
}}
>
{t.symbol} — {t.amountFormatted} (${t.balanceUSD.toFixed(2)})
</button>
</li>
))}
</ul>
);
}
// 3. Amount + deposit
return (
<div>
<input
value={state.amount}
onChange={(e) => dispatch({ type: "SET_AMOUNT", payload: e.target.value })}
placeholder="0.00"
/>
<button disabled={state.state !== "ready"} onClick={() => runExecute()}>
{state.state === "quoting" ? "Finding route…" : "Deposit"}
</button>
</div>
);
}
Wrap <CustomDepositFlow /> in the Providers shown above.
Analytics & your API key
Pass your app's apiKey (from the portal) in the config. Every event the
SDK emits (widget_loaded, quote_*, tx_initiated, tx_completed, tx_failed)
is sent to the depositOS API with an x-api-key header, so the portal can attribute
volume and transactions to your app. Completed deposits include a best-effort USD
value for volume reporting.