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/headless and 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.