Funding endpoints require a signed-in user session. Start with
Authentication before calling the execution routes below.
AGG exposes execution endpoints for deposit addresses, balance sync, withdrawals, positions, and
orders so partners can build funding and account views on top of the same user session.
How it works
User authenticates
Sign in via SIWE, SIWS, Google, or any supported provider.
Get deposit address
Call GET /execution/deposit-addresses to get the user’s wallet addresses and supported chains.
Returns 202 while the addresses are being prepared — poll until 200.
User sends USDC
The user sends USDC to a supported deposit address on the chain they prefer.
Balance updates
Call GET /execution/balances to see per-chain cash balances plus current venue positions.
Use POST /execution/sync-balances to force an on-chain sync if needed. For paginated activity,
use GET /execution/positions and GET /execution/orders.
Withdraw or continue
Use the same execution surface for withdrawals, positions, orders, and any account-level
funding UI in your app.
import { createAggClient } from "@agg-market/sdk";
type DepositAddressesResponse =
| {
ready: true;
evmAddress: string;
svmAddress: string;
supportedChains: Array<{
chainId: number;
name: string;
tokens: Array<{
symbol: string;
address: string;
decimals: number;
}>;
}>;
}
| { ready: false };
const client = createAggClient({
baseUrl: "https://api.agg.market",
appId: "your-app-id",
});
// After user authenticates...
// 1. Get deposit addresses (poll until ready)
async function getDepositInfo() {
while (true) {
const res = await client.request<DepositAddressesResponse>(
"/execution/deposit-addresses",
);
if (res.ready) {
return {
evmAddress: res.evmAddress, // Send USDC here on any EVM chain
svmAddress: res.svmAddress, // Send USDC here on Solana
chains: res.supportedChains, // Available chains + token addresses
};
}
// Deposit addresses are still being prepared — wait and retry
await new Promise((r) => setTimeout(r, 2000));
}
}
const deposit = await getDepositInfo();
console.log("EVM deposit address:", deposit.evmAddress);
console.log("Solana deposit address:", deposit.svmAddress);
console.log("Supported chains:", deposit.chains.map((c) => c.name));
// 2. Check balances
const balances = await client.getManagedBalances();
// balances.cash — per-chain token balances
// balances.positions — per-venue position balances
// 3. Force balance sync (after deposit)
await client.request<Record<string, never>>("/execution/sync-balances", {
method: "POST",
body: JSON.stringify({}),
});
import { useAggClient } from "@agg-market/hooks";
import { useQuery } from "@tanstack/react-query";
type DepositAddressesResponse =
| {
ready: true;
evmAddress: string;
svmAddress: string;
supportedChains: Array<{
chainId: number;
name: string;
tokens: Array<{ symbol: string; address: string; decimals: number }>;
}>;
}
| { ready: false };
function DepositInfo() {
const client = useAggClient();
const { data: deposit, isLoading } = useQuery({
queryKey: ["deposit-addresses"],
queryFn: () =>
client.request<DepositAddressesResponse>("/execution/deposit-addresses"),
refetchInterval: (query) => {
// Poll every 2s until deposit addresses are ready
return query.state.data?.ready ? false : 2000;
},
});
const { data: balances } = useQuery({
queryKey: ["managed-balances"],
queryFn: () => client.getManagedBalances(),
refetchInterval: 10_000, // Refresh every 10s
});
const { data: positions } = useQuery({
queryKey: ["execution-positions"],
queryFn: () => client.getExecutionPositions({ limit: 20 }),
enabled: !!deposit?.ready,
});
if (isLoading || !deposit?.ready) {
return <p>Preparing deposit addresses...</p>;
}
return (
<div>
<h3>Deposit USDC</h3>
<p>EVM address: <code>{deposit.evmAddress}</code></p>
<p>Solana address: <code>{deposit.svmAddress}</code></p>
<h4>Supported chains</h4>
<ul>
{deposit.supportedChains.map((chain) => (
<li key={chain.chainId}>
{chain.name} — {chain.tokens.map((t) => t.symbol).join(", ")}
</li>
))}
</ul>
{balances && (
<div>
<h4>Your balances</h4>
<pre>{JSON.stringify(balances.cash, null, 2)}</pre>
</div>
)}
{positions && (
<div>
<h4>Open positions</h4>
<p>{positions.data.length} grouped positions loaded</p>
</div>
)}
</div>
);
}
The @agg-market/ui package exports DepositModal and WithdrawModal for venue-level funding
and withdrawal UX. These components are presentational: you provide balances, handlers, and
any execution API calls behind them.import { useState } from "react";
import { DepositModal, WithdrawModal } from "@agg-market/ui/modals";
function FundingButtons() {
const [depositOpen, setDepositOpen] = useState(false);
const [withdrawOpen, setWithdrawOpen] = useState(false);
return (
<>
<button onClick={() => setDepositOpen(true)}>Deposit</button>
<button onClick={() => setWithdrawOpen(true)}>Withdraw</button>
<DepositModal
open={depositOpen}
onOpenChange={setDepositOpen}
venues={[
{ venue: "polymarket", balance: 125 },
{ venue: "kalshi", balance: 40 },
]}
onSelectVenue={(venue) => console.log("deposit venue", venue)}
onSelectDepositMethod={(venue, method) =>
console.log("deposit method", venue, method)
}
/>
<WithdrawModal
open={withdrawOpen}
onOpenChange={setWithdrawOpen}
venues={[
{ venue: "polymarket", balance: 125 },
{
venue: "kalshi",
balance: 40,
disabled: true,
disabledReason: "Complete Kalshi withdrawals on the Kalshi website.",
},
]}
onSelectVenue={(venue) => console.log("withdraw venue", venue)}
onSelectWithdrawMethod={(venue, method) =>
console.log("withdraw method", venue, method)
}
/>
</>
);
}
Fetch deposit addresses, execution balances, and withdrawal requests through the Execution API
separately, then pass the resulting state into your UI.
Withdrawals
Withdraw USDC to any external address.
type WithdrawResponse = {
sources: Array<{
chainId: number;
amountRaw: string;
txHash?: string;
}>;
};
const result = await client.request<WithdrawResponse>("/execution/withdraw", {
method: "POST",
body: JSON.stringify({
amountRaw: "50000000", // 50 USDC (6 decimals)
tokenSymbol: "USDC",
destinationAddress: "0x...", // External wallet address
destinationChainId: 137, // Optional preferred destination chain
}),
});
// result.sources — which chains the funds came from
for (const source of result.sources) {
console.log(`${source.amountRaw} from chain ${source.chainId}`);
if (source.txHash) console.log(` tx: ${source.txHash}`);
}
Supported chains
The supportedChains array in the deposit response tells you exactly which chains and tokens
are available. Common chains include:
| Chain | Use |
|---|
| Polygon (137) | Polymarket trading |
| Arbitrum (42161) | Low-fee deposits |
| Ethereum (1) | High-value deposits |
| Solana | Solana-native venues |
Users can deposit on any supported chain listed in the deposit-address response.
GET /execution/balances for managed cash balances and venue position balances.
GET /execution/positions for paginated open positions grouped by matched market.
GET /execution/orders for paginated execution activity.
Deposit detection
Deposits appear automatically after on-chain confirmation. There is no separate partner-side
confirmation step before the balance becomes visible in GET /execution/balances.
For faster UI feedback after a deposit, call POST /execution/sync-balances to trigger an
immediate on-chain balance refresh.