Client integration
This recipe assumes you’re building with React (Next.js, Remix, Vite, etc.). The same concepts apply elsewhere.
Install the building blocks
npm install @fractalshq/sync @fractalshq/auth@fractalshq/sync– React provider + hooks for distributions, claims, cohorts.@fractalshq/auth– Auth core (server + SIWS utilities) and React helpers (via@fractalshq/auth/react).
Environment variables to set
Wire both the public (client) and private (server) endpoints so your app knows where to talk to Auth and Sync:
AUTH_BASE_URL=https://auth.fractals.fun
NEXT_PUBLIC_AUTH_BASE_URL=/api/v1/fractals-auth
AUTH_INTERNAL_API_KEY=sk_live_xxx # server-only
SYNC_BASE_URL=https://sync.fractals.fun
NEXT_PUBLIC_SYNC_BASE_URL=/api/v1/sync # or your proxy path
SYNC_API_KEY=sk_sync_xxx # server-only
NEXT_PUBLIC_SYNC_API_KEY=pk_sync_xxx # optional if you expose read-only callsNEXT_PUBLIC_*values are safe for the browser (they usually point at your Next.js proxy routes).- Keep the
*_API_KEYsecrets on the server—only the proxy handler should read them.
Wrap your app
import { SyncProvider } from "@fractalshq/sync/react";
import { AuthProvider } from "@fractalshq/auth/react";
export function App() {
return (
<AuthProvider baseURL={process.env.NEXT_PUBLIC_AUTH_BASE_URL}>
<SyncProvider
baseUrl={process.env.NEXT_PUBLIC_SYNC_BASE_URL}
apiKey={process.env.NEXT_PUBLIC_SYNC_API_KEY}
>
<Dashboard />
</SyncProvider>
</AuthProvider>
);
}AuthProvider keeps a SIWS session alive (see Phantom’s SIWS primer ), while SyncProvider exposes hooks that already include your API key + environment. Under the hood, @fractalshq/auth/react also mounts tx-auth helpers so your app can request wallet signatures for server-initiated transactions (e.g., distribution funding, claims, or Ledger/hardware-wallet flows) without building nonce/relay plumbing manually.
Launching a distribution from the UI
import { useSyncApi } from "@fractalshq/sync/react";
import { useTxAuth } from "@fractalshq/auth/react";
export function FundCohortButton() {
const { distributions } = useSyncApi();
const { signAndSend } = useTxAuth();
async function handleClick() {
const { transaction, summary } = await distributions.create({
cohortId: "growth-users",
splitTemplateId: "weekly-50-50",
mint: "GEOD...",
schedule: {
startVestingTs: Math.floor(Date.now() / 1000),
endVestingTs: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60,
},
});
await signAndSend(transaction);
console.info(`Funded distribution ${summary.distributionId}`);
}
return <button onClick={handleClick}>Fund cohort</button>;
}cohortIdandsplitTemplateIdcome from the dashboard so you never reconstruct data locally.signAndSendreuses the wallet connection maintained byAuthProvider.
Adding a claim button
import { useSyncClaims } from "@fractalshq/sync/react";
export function ClaimRewards({ distributionId }: { distributionId: string }) {
const { fetchClaimTx } = useSyncClaims();
const { signAndSend } = useTxAuth();
async function claim() {
const { transaction, expectedAmount } = await fetchClaimTx({ distributionId });
await signAndSend(transaction);
alert(`Claimed ${expectedAmount} tokens`);
}
return <button onClick={claim}>Claim rewards</button>;
}Use the (coming soon) widget if you prefer a zero-code surface:
<SyncClaimWidget distributionId="dist_23" wallet={wallet} onClaimed={refreshStats} />Backend glue
For Next.js App Router:
// app/api/sync/[...route]/route.ts
import { createSyncHandler } from "@fractalshq/sync/server";
import { withApiAuth } from "@fractalshq/auth";
const handler = createSyncHandler({ apiKey: process.env.SYNC_API_KEY! });
export const GET = withApiAuth(handler);
export const POST = withApiAuth(handler);createSyncHandler proxies requests to Sync, injects your project ID, and respects cohort permissions. Pair it with Fractals Auth so every call already has an authenticated wallet session.