Skip to main content

Generating the publishable key

The calmKey you pass to <WagmiCalmProvider> is a publishable key minted in the Calm dashboard. Wagmi apps sign in with SIWE, so the key needs no identity-provider binding.
1

Open the Calm dashboard

Sign in to the Calm dashboard and open Publishable keys.
2

Fill out "Generate a new key"

  • EnvironmentSandbox to start, Live for production. Each environment issues its own key (calm_public_sandbox_… / calm_public_live_…).
  • Wallet provider — leave it on SIWE / none. Wagmi keys authenticate by wallet signature, with no IdP tenant to bind.
  • Allowed origin (optional) — the origin your app is served from. Live keys require an https:// origin; in Sandbox you can leave it blank to skip the Origin check (e.g. for http://localhost).
Calm dashboard generate-key form with the SIWE / none wallet provider

Calm dashboard: Generate a new key, SIWE / none

3

Generate and copy the key

Click Generate. The new key appears under Active keys — copy it and pass it as calmKey. It looks like calm_public_sandbox_<32 hex>.
A generated publishable key listed under Active keys with a copy button

Calm dashboard: the new key under Active keys

Installation

To add Calm to your project, install the required packages.
  • Wagmi is the wallet stack the SDK reads from for the connected account, chain, and signers.
  • Viem is the TypeScript interface for Ethereum that wagmi uses for blockchain operations.
  • TanStack Query is an async state manager that handles requests, caching, and more.

Import the stylesheet

Import the Calm stylesheet once at your app root (Next.js layout.tsx, React main.tsx):
or @import it from your own CSS file:

Wrap App in <WagmiCalmProvider>

Place <WagmiCalmProvider> inside the <WagmiProvider> and <QueryClientProvider> your wagmi app already sets up.
app/layout.tsx
Unlike the Privy and Dynamic providers (which take an rpcUrls prop), <WagmiCalmProvider> reads swap transaction receipts through your wagmi config — the per-chain transports above, routed by chain id. For production, point each swap source chain at a reliable RPC (e.g. http("https://…")) instead of the keyless http() default so the confirm step doesn’t stall.
Mount <WagmiCalmProvider> only while a wallet is connected — it reads the address from useAccount() at mount and requires it to be defined. Gate the mount on useAccount().status === "connected"; mounting with no connected account throws.

Open the onramp

Wrap any trigger element in <CalmOnramp> to open the deposit modal, and gate it on the Calm session via useSession. useSession creates the session automatically as soon as a wallet is connected — it runs the sign-in handshake on mount, not on a click. You gate the trigger on the result only so the modal can’t open before its requests would authenticate: the button stays disabled until session.data is ready.

Props

string
required
Your publishable key — calm_public_(live|sandbox)_<32 hex>. Embedded in the SIWE message’s Resources field as calm:credential:<calmKey> so the wallet attests the tenant key as part of the same signature that proves wallet ownership.
"usd" | "gbp" | "eur"
required
Source fiat currency for the bank-deposit onramp.
number
default:"1337"
Destination chain id for the delivered USDC. Defaults to HyperCore (1337).
string
default:"https://api.calmtreasury.xyz"
Override the Calm API root. Use https://api.sandbox.calmtreasury.xyz for the sandbox environment.

Errors

The provider’s session creation throws on any non-2xx response from the API. The useSession hook surfaces the error in result.error. See Errors for the full code table; the most common from this shell: