Deferred Flow Guide
Deferred mode gives each user an address at sign-in but creates no account on-chain. The XLM reserve is only sponsored when your backend calls POST /v3/wallets/fund, typically after a business event like KYC approval or a first deposit.
Turnkey wallets. For a co-signed or self-custody wallet (every new wallet on mainnet) the call answers
202 SERVER_WALLET_ACCOUNT_REQUESTEDwith arequestId: the account creation waits for the user, who approves it in their next session. Treat it as pending, not as an error. See the Server API.
This guide walks through the full implementation end-to-end.
Prerequisites
- Funding mode set to Deferred in Dashboard -> Wallets -> Account Funding (Stellar tab)
- A secret key from Dashboard -> Build -> API Keys
- That's it: no additional dashboard configuration required
How it works
Step 1: Gate unfunded wallets in the frontend
After login, decide whether to show your KYC/onboarding flow or the wallet UI. In Deferred mode the wallet exists but has no XLM reserve until activated. Pass the user's wallet.address (their G… public key) to your KYC flow so your backend can activate it later.
'use client';
import { usePollar } from '@pollar/react';
export function WalletGate() {
const { isAuthenticated, wallet } = usePollar();
if (!isAuthenticated) return <LoginButton />;
// Track "has this user completed your business trigger?" in your own backend.
// Until then, show the KYC/onboarding flow.
return <KycFlow publicKey={wallet?.address} />;
}Step 2: Trigger activation from your backend
When the business event occurs (KYC approved, first deposit confirmed, etc.), your backend calls POST /v3/wallets/fund using the secret key and the wallet's publicKey.
// Your backend: e.g. Next.js API route, Express handler, webhook receiver
async function fundWallet(publicKey: string) {
const response = await fetch('https://server.api.pollar.xyz/v3/wallets/fund', {
method: 'POST',
headers: {
'x-pollar-api-key': process.env.POLLAR_SECRET_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({ publicKey }),
});
if (!response.ok) {
const { code } = await response.json(); // { code, success: false }
throw new Error(`Funding failed: ${code}`);
}
return response.json();
// { content: { publicKey, startingBalance }, code: 'SERVER_WALLET_FUNDED', success: true }
}Never call this endpoint from the client. It requires your secret key; exposing it client-side compromises your entire app.
Step 3: Handle the response
| Code | Meaning | Action |
|---|---|---|
200 OK | Wallet funded successfully | Proceed: wallet is live on-chain |
400 Bad Request | Missing or malformed publicKey | Check the request payload |
402 Payment Required | Funding wallet has insufficient XLM | Top up via Dashboard -> Wallets -> Account Funding |
404 Not Found | publicKey is not a wallet owned by your app | Verify the public key |
409 Conflict | Wallet already funded | Safe to ignore; treat as success |
503 Service Unavailable | Stellar network issue | Pollar retries automatically |
Step 4: Notify the frontend
After activation, notify your frontend so the UI updates. Your backend owns the "is this user activated?" signal, so the simplest approach is to poll your own endpoint; you can confirm on-chain by refreshing the wallet balance (a funded wallet is live on-chain, with its reserve sponsored by the app's funding wallet plus the app's configured starting balance).
'use client';
import { usePollar } from '@pollar/react';
import { useEffect, useState } from 'react';
export function KycFlow({ publicKey }: { publicKey: string }) {
const { refreshWalletBalance, walletBalance } = usePollar();
const [activated, setActivated] = useState(false);
// Poll your own backend for the activation result, then refresh on-chain state.
useEffect(() => {
if (activated) return;
const interval = setInterval(async () => {
const done = await fetch('/api/activation-status').then(r => r.json());
if (done.activated) {
setActivated(true);
await refreshWalletBalance();
}
}, 2000);
return () => clearInterval(interval);
}, [activated, refreshWalletBalance]);
if (activated && walletBalance.step === 'loaded') {
return <p>✓ Wallet activated</p>;
}
return <p>Complete KYC to activate your wallet...</p>;
}Testing on testnet
- Set funding mode to Deferred in the Dashboard
- Log in: the wallet is created unfunded (no XLM reserve)
- Call your fund endpoint manually (e.g. with curl or Postman)
- Verify the wallet is now funded (its reserve is sponsored on-chain)
- Verify the G-address on Stellar Expert testnet
curl -X POST https://server.api.pollar.xyz/v3/wallets/fund \
-H "x-pollar-api-key: sec_testnet_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "publicKey": "GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }'Upgrade to SDK 0.12
Move an app on any @pollar release from 0.5 to 0.11 to 0.12 and API v3, one change at a time, with what to search for in your code.
Passkeys and wallet recovery
How a user keeps access to a Turnkey wallet when they lose the device: recovery passkeys, a confirmed email, a second device, and the phrase export.