Quickstart
This page walks through the most common flows with @magma-protocol/sdk. If you
have not installed the package yet, see Installation.
import { MagmaClient } from '@magma-protocol/sdk';
const magma = new MagmaClient();
All read flows below work with the default public client. The backing flow requires an authenticated client.
Browse the narrative feed
narratives.feed() returns a normalized, paginated response. Filter and sort
through NarrativeFeedParams:
const { narratives, total, page, has_more } = await magma.narratives.feed({
filter: 'active',
sort: 'top_score',
limit: 20,
});
console.log(`${total} narratives (page ${page})`);
for (const n of narratives) {
console.log(n.title, '·', n.score, '·', n.total_backed_sol, 'SOL');
}
The backend root feed currently returns only { narratives }. The SDK fills in
total, page, and has_more so you always get a stable shape — total falls
back to the returned count and has_more defaults to false.
Fetch a single narrative
const narrative = await magma.narratives.get('<NARRATIVE_ID>');
console.log(narrative.title, narrative.status, narrative.deadline_at);
The SDK unwraps the backend's { narrative: {...} } envelope and returns the
Narrative directly.
Read conviction
A wallet's conviction profile includes its tier, score, accuracy, and per-category stats:
const profile = await magma.users.getConvictionProfile('<WALLET>');
console.log('Tier:', profile.conviction_tier); // e.g. 'volcanic'
console.log('Score:', profile.conviction_score); // e.g. 847
console.log('Accuracy:', profile.accuracy_pct, '%');
console.log('Yield multiplier:', profile.yield_multiplier);
To read a wallet's Eruption Streak (which drives part of the yield multiplier):
const streak = await magma.users.getStreak('<WALLET>');
console.log('Streak:', streak.current_streak, '·', streak.streak_tier);
Submit a backing
Backing is a two-step flow: prepare and sign the Solana transaction with the user's wallet, then submit the signature so MAGMA records the position and routes principal into yield. This requires an authenticated client.
import { MagmaClient, MagmaError } from '@magma-protocol/sdk';
const magma = new MagmaClient({
authToken: privyJwtToken,
walletAddress: userWalletAddress,
});
try {
// 1 — Prepare the unsigned transaction (gasless via Kora if configured)
const { transaction, gasless } = await magma.narratives.prepareMint({
narrative_id: '<NARRATIVE_ID>',
backer_wallet: userWalletAddress,
amount_sol: 0.5,
});
// 2 — Sign with the user's wallet (Privy / Mobile Wallet Adapter)
const signedTx = await wallet.signTransaction(transaction);
// 3 — Record the backing on the backend
const result = await magma.narratives.back('<NARRATIVE_ID>', {
sol_amount: 0.5,
token_address: 'SOL',
tx_signature: signedTx.signature,
});
console.log('Success:', result.success);
console.log('Backing row:', result.backing.id, '· epoch', result.backing.epoch_number);
console.log('Combined yield multiplier:', result.backing.combined_yield_multiplier);
// `yield` is populated only when SOL was routed into Kamino, else null
if (result.yield) {
console.log('Yield active:', result.yield.active, '· est. APY', result.yield.estimatedApy);
}
} catch (err) {
if (err instanceof MagmaError) {
console.error(`[${err.status}] ${err.code}: ${err.message}`);
}
}
back() returns the full BackingResponse — { success, backing, yield } — where
backing is the complete narrative_backings row written by the backend and
yield is the Kamino deposit result (or null). See the
client reference for the full shape.
The SDK only retries idempotent GET requests. prepareMint, back, and
challenge are POST calls and never auto-retry, so a network blip can't
double-submit a transaction. See Error handling.
Read DeFi APYs and supported tokens
Live yield rates across all sources (Kamino, Save, Jito, Marinade, Jupiter, Meteora, Guardian, P0):
const { sources } = await magma.defi.getApys();
For a flattened, per-protocol token list — protocol key, label, supported token,
live APY, and availability — use getTokens():
const { tokens } = await magma.defi.getTokens();
for (const t of tokens) {
console.log(
t.protocol, // e.g. 'kamino'
t.label, // e.g. 'Kamino Lend'
t.token, // e.g. 'SOL/USDC'
t.apy, // live APY (percent), if available
t.testnet_available, // available on the current devnet deployment?
t.coming_at // when it goes live if not yet, else null
);
}
/v1/defi/apysThere is no standalone tokens endpoint. getTokens() derives the list by joining
the protocols metadata and the apys map from the same /v1/defi/apys response.
Pull the leaderboard
const { leaders } = await magma.leaderboard.get({
sort: 'score',
limit: 50,
});
leaders.forEach(l =>
console.log(`#${l.rank}`, l.wallet, '·', l.score, '·', l.tier),
);
For the streak-based leaderboard:
const { leaders } = await magma.leaderboard.getStreaks();
Read the current epoch
The Echo Pool epoch (via the nova resource):
const epoch = await magma.nova.getEpoch();
console.log(
`Epoch ${epoch.epoch_number}:`,
epoch.echo_pool_sol, 'SOL ·',
epoch.days_remaining, 'days left ·',
epoch.total_tickets, 'tickets',
);
Where to go next
- TypeScript client reference — every resource and method, with return types.
- x402 Payments — pay-per-call endpoints for agents.
- Error handling —
MagmaError, retries, and timeouts.