Skip to main content

API Reference

The complete MAGMA REST surface, grouped by resource. All paths are relative to:

https://api.magmaprotocol.xyz

Read the Overview for conventions, Authentication for the wallet-signed write model, and Errors for status codes. Method badges: GET POST PUT DELETE AUTH (credential or signature required).


Narratives

Prefix: /v1/narratives. The feed and lifecycle of narratives — read a single narrative or the feed, validate, polish, prepare a backing transaction, publish, and back an open market.

Unwrap single-narrative reads

GET /v1/narratives/:id returns the object wrapped under a narrative key. Always unwrap it (const n = data.narrative ?? data). GET /v1/narratives/:id/rules likewise wraps under rules. A narrative score of exactly 0 means scoring is pending — render it as a placeholder, not a real 0. See Conventions.

Get feed

GET /v1/narratives/

Query paramTypeDescription
filterstringall | new | trending | backed. Default all.
categorystringOne of the 24 category enums (see below). Optional.
sub_categorystringSub-category filter. Optional.
asset_tagstringAsset tag filter. Optional.
durationstringDuration / deadline-tag filter. Optional.
sortstringSort order. Optional.
walletstringRequired when filter=backed.
limitinteger1–100 for the public feed; the broad listing accepts a large cap (up to 5000). Default 20.

Categories (24): MARKET, ECOSYSTEM, SPORTS, ESPORTS, SOCIAL, CULTURAL, LEGAL, POLITICAL, SCIENTIFIC, GEOPOLITICAL, CONVICTION, ECONOMICS, TECHNOLOGY, HEALTH, CLIMATE, BUSINESS, ONCHAIN, SATIRE, BUILDER, CAST, COMMODITIES, MACRO, EQUITIES, FOREX. See Narrative categories for the full taxonomy.

curl 'https://api.magmaprotocol.xyz/v1/narratives/?filter=trending&limit=20'
{
"narratives": [
{
"id": "0b3f…",
"wallet_address": "7xKX…9fПb",
"title": "BTC above $120k by Q3 2026",
"thesis": "Will Bitcoin close above $120,000 on any day before September 30 2026 per CoinGecko?",
"status": "active",
"score": 72,
"sol_backed": 4.2,
"backers": 8,
"deadline_at": "2026-07-08T00:00:00Z",
"deadline_tag": "LONG",
"category": "MARKET",
"narrative_type": "MARKET",
"is_protocol_narrative": true,
"protocol_narrative_label": "MAGMA Protocol",
"uncertainty_score": 65,
"created_at": "2026-04-06T12:00:00Z"
}
]
}

Get single narrative

GET /v1/narratives/:id

Returns the narrative wrapped under a narrative key — you must unwrap it (const n = data.narrative ?? data). A pre-market narrative carries is_pre_market: true and an opens_at timestamp; gate backing on it (see Back a narrative).

{ "narrative": { "id": "0b3f…", "title": "…", "score": 72, "is_pre_market": false, "opens_at": null } }

Get hero narratives

GET /v1/narratives/hero

Curated hero/featured narratives for the landing surface.

{ "narratives": [ { "id": "0b3f…", "title": "…" } ] }

Filter counts

GET /v1/narratives/filter-counts

Aggregate counts used to drive filter chips and a live "active markets" badge.

{
"total_active": 312,
"categories": { "MARKET": 88, "ECOSYSTEM": 41 },
"durations": { "SHORT": 120, "LONG": 192 },
"sub_categories": { "BTC": 30 }
}

Score history

GET /v1/narratives/:id/score-history

Time series of the narrative's score for charting.

Market history

GET /v1/narratives/:id/market-history

Market-event time series (volume/backing points). Returns a note of market_event_unavailable with an empty points array when no events exist yet.

{ "points": [], "note": "market_event_unavailable" }

Rules

GET /v1/narratives/:id/rules

Resolution rules for the narrative, wrapped under a rules key. Returns 404 when the narrative has no rules attached.

{ "rules": { "resolution_source": "CoinGecko", "criteria": "…" } }

Generate (AI)

POST AUTH /v1/narratives/generate

Kicks off async AI narrative generation and returns a jobId. Poll GET /v1/narratives/generate/status/:jobId for completion.

Check originality

POST /v1/narratives/check-originality

Scores a thesis for novelty before submission.

{ "thesis": "Will Bitcoin reach $200k before end of 2026?" }
{
"ok": true,
"similarity": 12,
"score": 74,
"suggested_category": "MARKET",
"message": "Your thesis appears original."
}

Polish text (AI)

POST AUTH /v1/narratives/polish-text

Rewrites a rough thesis into a crisp, resolvable question. Rate-limited to 3 per wallet per day (rate limits); responds in the input's language.

{ "thesis": "bitcoin will hit 200k", "wallet_address": "7xKX…9fПb" }
{
"ok": true,
"polished": "Will Bitcoin reach $200,000 before December 31 2026 per CoinGecko?",
"original": "bitcoin will hit 200k"
}

Polish voice

POST AUTH /v1/narratives/polish-voice

Transcribes/cleans a spoken thesis. Shares the daily polish pool (3/day).

{ "transcript": "um so i think bitcoin will like hit two hundred k before the year ends", "wallet_address": "7xKX…9fПb" }
{ "ok": true, "polished": "Will Bitcoin reach $200,000 before December 31 2026 per CoinGecko?" }

Prepare mint (build backing transaction)

POST AUTH /v1/narratives/prepare-mint

Builds the unsigned backing transaction. Sign + send it, then call publish.

Body fieldTypeDescription
backer_walletstringBacker's wallet address.
amount_lamportsintegerBacking amount in lamports.
deadline_daysintegerNarrative resolution window in days.
narrative_idstringTarget narrative UUID.
{ "transaction": "AqwF…base64-unsigned-tx…", "narrativeId": "0b3f…", "deadlineTimestamp": 1789200000 }

Publish narrative

POST AUTH /v1/narratives/publish

Submits the signed transaction and records the narrative on devnet. Publishing is gated by an anti-spam publish fee of ~5 SOL (NARRATIVE_PUBLISH_FEE_SOL; ~80% becomes the creator's own locked backing stake, ~20% treasury — see YBNCM → publish fee) plus a Cloudflare Turnstile check.

Body fieldTypeDescription
walletAddressstringCreator wallet.
thesisstringThe resolvable question.
categorystringCategory enum.
deadline_daysintegerResolution window.
signaturestringTransaction signature from the signed prepare-mint tx (pays the publish fee).
cf_tokenstringCloudflare Turnstile token (required).
{ "success": true, "narrativeId": "0b3f…", "message": "Narrative published to Solana Devnet" }

Common errors: 400 TURNSTILE_FAILED, 403 conviction_score_required, 422 narrative_too_obvious, 422 content_flagged, 429 daily_limit_reached.

Back a narrative

POST AUTH /v1/narratives/:id/back

Backs an open market on one side. side selects the YES ('true') or NO ('false') outcome.

Body fieldTypeDescription
amount_solnumberBacking amount in SOL (minimum 0.01).
token_typestringBacking token, e.g. SOL.
sidestring'true' (YES) | 'false' (NO).
{ "amount_sol": 1.5, "token_type": "SOL", "side": "true" }

When the narrative is still pre-market (is_pre_market: true), backing is rejected with 403:

{ "error": "market_not_open", "opens_at": "2026-07-01T00:00:00Z" }

Gate your UI on is_pre_market and surface opens_at rather than prompting a signature that will be refused. See Conventions.


Narrative Groups

Prefix: /v1/narrative-groups. Grouped markets (a parent narrative with member narratives) carrying live volume and backer aggregates.

List groups

GET /v1/narrative-groups

Query paramTypeDescription
featuredbooleanOnly featured groups. Optional.
limitintegerPage size. Optional.
min_volumenumberMinimum total volume (USD) filter. Optional.
min_backersintegerMinimum total backers filter. Optional.

total_volume_usd and total_backers are live aggregates. Member narratives carry is_pre_market, opens_at, and pre_market_source so you can render the pre-market gate per member.

{
"groups": [
{
"id": "g1a2…",
"title": "2026 Macro",
"total_volume_usd": 18420.0,
"total_backers": 64,
"narratives": [
{ "id": "0b3f…", "title": "…", "is_pre_market": true, "opens_at": "2026-07-01T00:00:00Z", "pre_market_source": "admin" }
]
}
]
}

Get group

GET /v1/narrative-groups/:id

Returns the group wrapped under a group key (with its narratives array). Unwrap it (const g = data.group ?? data). See Conventions.

{ "group": { "id": "g1a2…", "title": "2026 Macro", "narratives": [ /* … */ ] } }

Conviction

Prefix: /v1/conviction. A wallet's Conviction Score, tier, multipliers, fees, streaks, and echo-pool preview. Tiers, low → high: ember → flare → magma → core → volcanic.

Get conviction profile

GET /v1/conviction/:wallet

curl 'https://api.magmaprotocol.xyz/v1/conviction/<wallet>'
{
"conviction_score": 420,
"conviction_tier": "magma",
"correct_backings": 42,
"incorrect_backings": 8,
"accuracy_rate": 84.0,
"current_streak": 5,
"longest_streak": 12,
"conviction_multiplier": 1.6,
"streak_multiplier": 1.1,
"combined_multiplier": 1.76,
"fee_pct": 1.5,
"terms_accepted": true,
"terms_version": "0.1",
"terms_accepted_at": "2026-04-01T10:00:00Z",
"per_category_stats": {
"MARKET": { "backed": 30, "correct": 26, "accuracy": 87 }
}
}

An unseen wallet returns a zeroed profile (conviction_tier: "ember", multipliers 1.0, fee_pct: 2.0) rather than a 404.

Echo-pool preview

GET /v1/conviction/echo-pool/preview/:wallet

Estimated Echo Pool distribution for the wallet at the current epoch.

Echo-pool history

GET /v1/conviction/echo-pool/history/:wallet

Last 12 epochs of Echo Pool distributions for the wallet.

Creator profile

GET /v1/conviction/creator/:wallet

Creator score, tier, share percentage, and narrative counts.

{
"creator_score": 180,
"creator_tier": "flare",
"creator_share_pct": 5,
"total_creator_earnings_sol": 1.23,
"narratives_submitted": 14,
"narratives_resolved_true": 9,
"narratives_pending": 3
}

Epoch (Echo Pool)

GET /v1/conviction/epoch/current

The current Echo Pool epoch — number, window, time remaining, accumulated SOL, and per-pool breakdown.

{
"ok": true,
"epoch_number": 7,
"start_date": "2026-04-01T00:00:00Z",
"end_date": "2026-04-15T00:00:00Z",
"days_remaining": 5,
"total_accumulated_sol": 128.4,
"pools": { "conviction": 64.2, "creator": 32.1 }
}

GET /v1/conviction/epoch/history · GET /v1/conviction/epoch/preview/:wallet

Past epochs, and a per-wallet projection for the current epoch.

Eruption

GET /v1/conviction/eruption/:wallet

A wallet's Eruption (streak/burst) state.

Leaderboards

GET /v1/conviction/leaderboard/conviction · GET /v1/conviction/leaderboard/creators

Top wallets by conviction score and by creator score, respectively. Both accept ?limit= (default 50) and ?offset= for paging.


Missions

Prefix: /v1/missions. Per-wallet missions, completion checks, and a missions leaderboard.

Get missions

GET /v1/missions/:wallet

The wallet's missions, typically grouped by category, with progress and completion state.

Check completion

POST /v1/missions/check/:wallet

Re-evaluates the wallet's missions and marks any newly satisfied ones complete.

Leaderboard

GET /v1/missions/leaderboard

Query paramTypeDescription
sortstringmissions_completed | conviction_score | epoch_performance.
limitintegerPage size. Default 50.

DeFi

Prefix: /v1/defi. Read protocol APYs and route principal into yield. The current DeFi integration set is Kamino, Save, Jito, Marinade, Jupiter (Lend), Meteora, Guardian, and Project 0 (P0).

Devnet availability

Kamino and Save have devnet markets, so their deposits build and submit real devnet transactions. Jito, Marinade, Jupiter Lend, Meteora, Guardian, and P0 are mainnet-targeted: their endpoints return 503 coming_soon (or 503 p0_disabled) until wired. Each protocol's status is reported in the protocols map of GET /v1/defi/apys via testnet_available.

Get protocol APYs

GET /v1/defi/apys

Latest APYs (Redis-cached, falling back to defaults) plus per-protocol metadata.

curl 'https://api.magmaprotocol.xyz/v1/defi/apys'
{
"ok": true,
"source": "redis",
"polled_at": "2026-04-09T12:00:00Z",
"apys": {
"kamino": 9.2, "kamino_sol": 7.2, "kamino_usdc": 5.8,
"save": 7.1, "jito": 7.8, "marinade": 7.2,
"meteora": 18.4, "jupiter_lend": 4.8, "p0": 8.5
},
"protocols": {
"kamino": { "label": "Kamino Lend", "token": "SOL/USDC", "testnet_available": true, "coming_at": null },
"save": { "label": "Save Finance", "token": "SOL/USDC", "testnet_available": true, "coming_at": null },
"jito": { "label": "Jito Staking", "token": "SOL", "testnet_available": false, "coming_at": "mainnet" },
"marinade": { "label": "Marinade", "token": "SOL", "testnet_available": false, "coming_at": "mainnet" },
"p0": { "label": "Project 0", "token": "Multi", "testnet_available": false, "coming_at": "mainnet" }
},
"borrow_enabled": false
}

Generic deposit (prepare / confirm)

The protocol-agnostic flow auto-routes by token and returns an unsigned tx for client signing. Supports kamino, save, jupiter_lend, marinade, jito.

POST AUTH /v1/defi/deposit/prepare

Body fieldTypeDescription
walletstringDepositor wallet.
token_symbolstringe.g. SOL, USDC. Drives auto-routing.
amountnumberUI amount. Minimum 0.01 SOL.
protocolstringOptional explicit protocol override.
narrative_idstringOptional; direct for a standalone earn deposit.
{
"ok": true,
"transaction": "AqwF…base64-unsigned-tx…",
"blockhash": "9xQe…",
"backing_id": "c1a2…",
"protocol": "kamino",
"amount_sol": 1.5,
"token_symbol": "SOL"
}

POST AUTH /v1/defi/deposit/confirm

Verifies the signed tx on-chain and marks the backing confirmed. Body: { backing_id, tx_signature, wallet }.

{ "ok": true, "backing_id": "c1a2…", "tx_signature": "5Hb…", "amount_sol": 1.5, "protocol": "kamino" }

Generic withdrawal (prepare / confirm)

POST AUTH /v1/defi/withdrawal/prepare · POST AUTH /v1/defi/withdrawal/confirm

Mirror of deposit. Body for prepare: { backing_id, wallet }; for confirm: { backing_id, tx_signature, wallet }. Supports kamino, save, jupiter_lend, marinade. Jito liquid unstaking is not supported — swap jitoSOL on Jupiter instead (503 jito_unstake_not_supported).

Per-protocol deposit endpoints

These build a protocol-specific transaction directly.

EndpointMethodBodyNotes
/v1/defi/kamino/depositPOST{ wallet_address, amount_sol, narrative_id? }Returns a receipt. Devnet-live.
/v1/defi/kamino/withdrawPOST{ wallet_address, amount_sol, narrative_id, receipt }Returns yield_earned_sol.
/v1/defi/save/depositPOST{ wallet_address, symbol, amount_base }Multi-tx, ready_to_sign. Devnet-live.
/v1/defi/save/withdrawPOST{ wallet_address, symbol, amount_base }Multi-tx, ready_to_sign.
/v1/defi/jito/depositPOST{ wallet_address, amount_sol }Returns jitosol_account. Mainnet.
/v1/defi/marinade/depositPOST{ wallet_address, amount_sol }Returns msol_account. Mainnet.
/v1/defi/marinade/withdrawPOST{ wallet_address, amount_sol }Unstake. Mainnet.
/v1/defi/jupiter-lend/depositPOST{ wallet_address, symbol, amount_raw }Versioned tx. Mainnet.
/v1/defi/jupiter-lend/withdrawPOST{ wallet_address, symbol, amount_raw }Mainnet.
/v1/defi/meteora/depositPOST503 coming_soon (pool config pending).
curl -X POST 'https://api.magmaprotocol.xyz/v1/defi/jito/deposit' \
-H 'Content-Type: application/json' \
-d '{ "wallet_address": "7xKX…9fПb", "amount_sol": 2.0 }'
{ "ok": true, "protocol": "jito", "jitosol_account": "…", "status": "ready_to_sign" }

Project 0 (P0)

P0 is a unified-margin integration gated at Core tier (600+ Conviction Score) for account/strategy reads, and behind a p0_enabled config flag for deposits.

EndpointMethodPurpose
/v1/defi/p0/depositPOST AUTHBuild deposit tx(s). Body: { wallet_address, asset_mint, amount_ui, narrative_id? }.
/v1/defi/p0/deposit/confirmPOST AUTHRecord confirmed deposit.
/v1/defi/p0/withdrawPOST AUTHBuild withdraw tx(s). Body: { wallet_address, asset_mint, amount_ui?, withdraw_all? }.
/v1/defi/p0/withdraw/confirmPOST AUTHClose position. Body: { wallet_address, position_id }.
/v1/defi/p0/health/:walletGETAccount health for a wallet.
/v1/defi/p0/positions/:walletGETOpen P0 positions.
/v1/defi/p0/account/:walletGETAccount summary. Core tier gated.
/v1/defi/p0/strategiesGETAvailable strategies (?wallet= gates at Core).
{
"ok": true,
"protocol": "p0",
"account_address": "Hk9…",
"needs_account_creation": false,
"transactions": 2,
"status": "ready_to_sign",
"note": "Sign all transactions with MWA in order. Call /v1/defi/p0/deposit/confirm after signing."
}

When P0 is off: 503 { "error": "p0_disabled", "message": "Project Zero integration coming soon." }.

Allocation & yield

GET /v1/defi/allocation/:wallet

Active DeFi positions for a wallet, with per-position backing_id, protocol, amount, percentage split, and can_withdraw.

{
"ok": true,
"wallet": "7xKX…9fПb",
"positions": [
{ "backing_id": "c1a2…", "protocol": "kamino", "token_symbol": "SOL", "amount_sol": 1.5, "yield_earned_sol": 0.012, "status": "confirmed", "can_withdraw": true }
],
"allocation": [ { "protocol": "kamino", "amount_sol": 1.5, "percentage": 100.0, "backing_id": "c1a2…" } ],
"total_sol": 1.5,
"empty": false
}

GET /v1/defi/yield/:wallet

Total yield earned across all DeFi positions plus an echo-pool breakdown.

{
"ok": true,
"wallet": "7xKX…9fПb",
"yield_earned_sol": 0.054,
"breakdown": { "narrative_yield_sol": 0.012, "echo_pool_sol": 0.042 }
}

Staking

Prefix: /v1/staking. A wallet's MAGMA staking position and tier.

Testing on devnet

MAGMA staking is currently in testing on devnet — the staking deposit flow is gated off (coming_soon) until mainnet. The read below still returns the wallet's position shape.

Get staking position

GET /v1/staking/:wallet

{
"wallet_address": "7xKX…9fПb",
"staked_amount": 0,
"tier": "ember",
"positions": []
}

Borrow

Prefix: /v1/borrow. Borrow against lending positions through Kamino and Save, with LTV scaled by Conviction tier. Opening a position requires accepting borrow terms; on devnet, borrow_enabled may be off (503 borrow_disabled).

Get borrow rates

GET /v1/borrow/rates

Current borrow APRs for Kamino and Save (60s cache), with the MAGMA spread applied (50 bps).

{
"ok": true,
"source": "redis",
"rates": {
"kamino": { "base": { "sol": 3.2, "usdc": 5.1 }, "with_spread": { "sol": 3.7, "usdc": 5.6 }, "magma_spread_bps": 50 },
"save": { "base": { "sol": 2.9, "usdc": 4.8 }, "with_spread": { "sol": 3.4, "usdc": 5.3 }, "magma_spread_bps": 50 },
"polled_at": "2026-04-09T12:00:00Z"
}
}

Get capacity

GET /v1/borrow/capacity/:wallet

Borrowing power from the wallet's tier and open positions.

{ "ok": true, "wallet": "7xKX…9fПb", "conviction_tier": "Magma", "max_ltv": 0.65, "total_borrowed_usd": 120.50, "open_positions": 1 }

Simulate borrow

GET /v1/borrow/simulate

Query paramTypeDescription
walletstringBorrower wallet.
protocolstringkamino | save.
assetstringBorrow asset symbol, e.g. USDC.
amount_usdnumberRequested borrow size in USD.
{
"ok": true,
"simulation": {
"borrow_amount_usd": 500,
"max_ltv": 0.65,
"collateral_required_usd": 769.23,
"estimated_health_factor": 1.308,
"warning": null
}
}

Prepare / confirm borrow

POST AUTH /v1/borrow/prepare

Validates capacity and returns borrow params for confirmation. Requires borrow_terms_accepted = true (403 terms_not_accepted otherwise) and borrow_enabled (503 borrow_disabled otherwise).

Body fieldTypeDescription
walletstringBorrower wallet.
protocolstringkamino | save.
borrow_assetstringAsset symbol.
borrow_asset_mintstringAsset mint (optional).
amount_usdnumberBorrow size in USD.
{
"ok": true,
"borrow_id": "b71f…",
"max_ltv": 0.65,
"borrow_apy": 5.1,
"collateral_required_usd": 769.23,
"estimated_health_factor": 1.308,
"status": "ready_to_confirm"
}

POST AUTH /v1/borrow/confirm

Records the opened position.

{ "wallet": "7xKX…", "protocol": "kamino", "borrow_asset": "USDC", "amount_usd": 500, "borrow_apy": 5.1, "max_ltv_tier": "magma" }

Repay

POST AUTH /v1/borrow/repay/prepare · POST AUTH /v1/borrow/repay/confirm

Prepare returns principal + accrued interest + total repay for a position_id; confirm closes the position. Body: { wallet, position_id }.

Health & positions

GET /v1/borrow/health/:wallet · GET /v1/borrow/positions/:wallet

Health factors and full details for all open borrow positions.

Accept borrow terms

POST /v1/borrow/accept-terms

{ "wallet": "7xKX…9fПb" }

Fast action

POST AUTH /v1/borrow/fast-action

One-tap preset borrow. Requires Flare tier (100+ score) (403 flare_required otherwise).

Body fieldTypeDescription
walletstringBorrower wallet.
actionstringsafe (30% of max LTV) | balanced (50%) | max (100%) | instant_sol (40%).
protocolstringOptional, default kamino.
borrow_assetstringOptional, default USDC.
{ "ok": true, "action": "safe", "max_ltv": 0.65, "effective_ltv": 0.195, "ltv_pct_of_max": 0.3, "status": "ready_to_confirm" }

Verify

Prefix: /v1/verify. Identity verification across chains. Supported methods for Solana wallets: Civic, Gitcoin (Passport), and SAS (Solana Attestation Service). EVM wallets fall back to Gitcoin (+ Human Protocol, coming soon).

Get verification status

GET /v1/verify/status/:wallet

Detects the chain from the address and returns per-method state.

{
"ok": true,
"wallet": "7xKX…9fПb",
"chain": "solana",
"available_methods": ["civic", "gitcoin", "sas"],
"verification": {
"civic_verified": true,
"gitcoin_score": 24,
"gitcoin_verified": true,
"sas_verified": false
},
"fully_verified": true,
"recommended_method": "civic"
}

gitcoin_verified is true at score ≥ 10; the Passport check endpoint enforces a passing threshold of 20.

Initiate verification

POST /v1/verify/initiate

Returns the flow config (provider URL, callback, type) for the chosen or chain-default method.

{ "wallet": "7xKX…9fПb", "preferred_method": "civic" }
{
"ok": true,
"chain": "solana",
"flow": {
"method": "civic",
"url": "https://getpass.civic.com",
"callback": "/v1/verify/civic",
"type": "oauth",
"description": "Civic Pass — biometric identity verification for Solana wallets"
}
}

Method endpoints

EndpointMethodBody / paramsPurpose
/v1/verify/civicPOST{ token, wallet_address }Validate a Civic Pass token.
/v1/verify/passport/:walletGETpath walletCheck Gitcoin Passport score (threshold 20).
/v1/verify/sasPOST{ wallet_address, attestation_id? }SAS attestation (records intent; coming_soon).
/v1/verify/sas/attestations/:walletGETpath walletList SAS on-chain attestations.
/v1/verify/confirmPOST{ wallet_address, method, verification_id?, chain? }Provider callback writer. methodcivic | gitcoin | sas.
/v1/verify/skr/:walletGETpath walletVerify SKR balance + 45-day hold; unlocks Echo Pool ticket boost & deposit-fee reduction.
// GET /v1/verify/passport/<wallet>
{ "ok": true, "verified": true, "score": 24, "wallet_address": "7xKX…9fПb" }

KYC

Prefix: /v1/kyc. Persona-backed identity verification, KYC status / tier, and wallet (OFAC) screening.

Persona sandbox

KYC currently runs against Persona in sandbox mode (template itmpl_6gvRNu9U3r5NokYRF3XhXb2X7whj) ahead of mainnet. Treat verifications as test-only until production is enabled.

Start verification

POST /v1/kyc/start

Opens a Persona inquiry and returns a hosted kyc_url to redirect the user to. If the wallet is already verified it returns { already_verified: true, kyc_tier }.

Body fieldTypeDescription
walletstringWallet to verify.
tierintegerRequested KYC tier 1 | 2. Optional.
{ "inquiry_id": "inq_…", "session_token": "…", "kyc_url": "https://withpersona.com/verify?inquiry-id=inq_…" }

Get KYC status

GET /v1/kyc/status/:wallet

{
"wallet_address": "7xKX…9fПb",
"kyc_tier": 1,
"kyc_status": "approved",
"ofac_screened": true,
"kyc_completed_at": "2026-04-10T12:00:00Z",
"tier_limits_usd": { "daily": 1000, "monthly": 10000 }
}

kyc_tier is 0–4. kyc_status is one of: none, pending, approved, declined, needs_review, expired, erased, watchlist_flagged.

Screen wallet

POST /v1/kyc/screen-wallet

Runs a blockchain-address (OFAC) screen, typically called after KYC completes.

Body fieldTypeDescription
walletstringMAGMA wallet.
blockchain_addressstringAddress to screen.
{ "cleared": true, "status": "clear", "blockchain_address": "7xKX…9fПb" }

The flow is: POST /v1/kyc/start → redirect to kyc_urlGET /v1/kyc/status/:walletPOST /v1/kyc/screen-wallet.


NEAR Intents

Prefix: /v1/intents. Cross-chain swaps routed through NEAR Intents. The asset catalog covers ~156 tokens (cached ~1 hour).

Token & quote shape

Tokens have no icon field — resolve icons client-side (e.g. a CoinGecko map). originAsset / destinationAsset must be the token assetId, not its symbol, and amount / amountIn are strings, not numbers.

List tokens

GET /v1/intents/tokens

{
"tokens": [
{ "assetId": "nep141:…", "symbol": "SOL", "blockchain": "solana", "decimals": 9, "contractAddress": null, "price": 152.3 }
]
}

Quote

POST AUTH /v1/intents/quote

Body fieldTypeDescription
originAssetstringSource token assetId.
destinationAssetstringDestination token assetId.
amountstringInput amount as a string.
recipientstringDestination-chain address (see below).
refundTostringRefund address — always the origin (Solana) wallet.
walletAddressstringThe user's wallet.

recipient must match the destination chain's address format: a Solana base58 address for solana (auto-filled from the wallet), a NEAR account ID (e.g. alice.near) for near, or an EVM 0x… address for eth / base / arbitrum.

Confirm

POST AUTH /v1/intents/confirm

Returns the depositAddress to send funds to.

Body fieldTypeDescription
depositAddressstringDeposit address from the quote.
walletAddressstringThe user's wallet.
originAsset / destinationAssetstringToken assetIds.
originChain / destinationChainstringSource / destination blockchains.
amountInstringInput amount as a string.
txHashstringOptional source-chain tx hash.

Status & history

GET /v1/intents/status/:depositAddress · GET /v1/intents/history/:wallet

Status terminal states are SUCCESS, REFUNDED, and FAILED — stop polling on is_terminal: true.

{ "status": "SUCCESS", "is_terminal": true }

SideShift

Prefix: /v1/sideshift. A thin proxy over SideShift for cross-chain swaps, gated by a configured affiliate ID.

Access gated

SideShift currently returns ACCESS_DENIED because the upstream provider has blocked the server's region. The endpoints below are wired and resume working once the affiliate access is restored.

List coins

GET /v1/sideshift/coins

The full supported-coin list (no icon field — resolve icons client-side).

{ "ok": true, "coins": [ { "coin": "BTC", "name": "Bitcoin", "networks": ["bitcoin"], "hasMemo": false } ] }

Quote

POST /v1/sideshift/quote

Body: { fromCoin, toCoin, fromAmount }.

Shift & status

POST /v1/sideshift/shift · GET /v1/sideshift/shift/:id

Create a shift and poll it. Terminal statuses: settled, complete, failed, refunded, expired.


TRON / Wormhole

Prefix: /v1/tron. TRON bridge configuration and Wormhole VAA status, used for the USDT-TRC20 bridge path via Wormhole.

Gated on vault deployment

The TRON LockVault is not deployed yet: GET /v1/tron/config returns vault_deployed: false and status: 'coming_soon'. Gate any TRON UI on vault_deployed: true.

Get config

GET /v1/tron/config

{ "ok": true, "vault_deployed": false, "chain_id_wormhole": 9, "status": "coming_soon" }

VAA status

GET /v1/tron/vaa-status/:txHash

Wormhole VAA status for a TRON transaction. Poll on the returned interval (15s) and stop when is_terminal: true.

{ "ok": true, "status": "pending", "is_terminal": false, "poll_again": true, "poll_interval_ms": 15000 }

status is one of pending, signed, or not_found.


Users

Prefix: /v1/users. Per-wallet profile, history, holdings, and aggregated portfolio.

Transaction history

GET /v1/users/:wallet/transactions

Query paramTypeDescription
typestringbacking | payout | creator_earn. Omit for all.
limitintegerDefault 50, max 200.
{
"ok": true,
"wallet": "7xKX…9fПb",
"transactions": [
{
"id": "c1a2…",
"type": "backing",
"amount_sol": 2.5,
"token_type": "SOL",
"yield_earned": 0.042,
"narrative": { "id": "0b3f…", "title": "…", "status": "graduated" },
"created_at": "2026-04-01T10:00:00Z",
"status": "confirmed"
}
],
"echo_pool_epochs": []
}

Other user endpoints

EndpointMethodPurpose
/v1/users/:wallet/profileGETPublic profile (username, tier, accuracy).
/v1/users/:wallet/profilePUTUpdate profile (username uniqueness + NFT-ownership checks).
/v1/users/:wallet/balanceGETScores, totals, active positions, whitelist flag.
/v1/users/:wallet/backingsGETPaginated backings (?page=, ?status=) with total.
/v1/users/:wallet/backedGETAll backed narratives + total_backed_sol.
/v1/users/:wallet/payoutsGETPayout history + total_earned.
/v1/users/:wallet/narrativesGETNarratives created by the wallet.
/v1/users/:wallet/nftsGETTier NFTs held by the wallet.
/v1/users/:wallet/activityGETUnified activity feed for the wallet.
/v1/users/:wallet/portfolioGETFull aggregation: conviction, ruffler, staking, yield pools.
/v1/users/:wallet/yield-summaryGETTotal yield earned (total_yield_earned_sol, total_yield_earned_usd, by_narrative). Never 404 — returns zeroes when no yield.
/v1/users/:wallet/creator-royaltiesGETCreator royalty history (total_royalties_sol, count, royalties). ?limit= (max 200, default 50).
/v1/users/path-choicePOSTOnboarding path.
/v1/users/verify-holdingsPOSTRe-check SKR holding (24h cache). Body { wallet }.
/v1/users/push-tokenPOSTRegister a push token.

Path choice

POST /v1/users/path-choice

{ "wallet_address": "7xKX…9fПb", "path_choice": "creator" }

Canonical paths: creator | backer | yield_farmer | explorer. Legacy aliases predictor → backer, defi → yield_farmer, observer → explorer are accepted.


SAS Attestations

Prefix: /v1/verify/sas. Solana Attestation Service (SAS) tier badges for a wallet — read the on-chain attestations that back a wallet's KYC, conviction, and creator status.

Devnet

SAS attestations are registered on devnet; mainnet registration is pending before launch.

Get attestations

GET /v1/verify/sas/attestations/:wallet

{
"ok": true,
"wallet": "7xKX…9fПb",
"attestations": { "kyc_tier": 1, "conviction_tier": "magma", "creator": true }
}

To record SAS attestation intent, see POST /v1/verify/sas in Verify.


Notifications

Prefix: /v1/notifications. The in-app notification feed, read state, and Web Push subscription.

Building

The notifications system is under construction — endpoints are wired but the feed is still being populated end-to-end. For the push-subscription and webhook integration view (including the full list of notification types), see Webhooks.

Feed & read state

EndpointMethodPurpose
/v1/notifications/:walletGETNotification feed. ?limit= (default 50), ?offset=, ?unread_only= (default false).
/v1/notifications/:wallet/unread-countGETUnread badge count.
/v1/notifications/:wallet/mark-readPOSTMark specific notifications read.
/v1/notifications/:wallet/mark-all-readPOSTMark all read.
/v1/notifications/:wallet/:notification_idDELETEDelete one notification.

Web Push

EndpointMethodPurpose
/v1/notifications/push/vapid-public-keyGETVAPID public key for the push subscription.
/v1/notifications/push/subscribePOSTRegister a Web Push subscription.
/v1/notifications/push/preferences/:walletGETRead per-type push preferences.
/v1/notifications/push/preferences/:walletPUTUpdate per-type push preferences.

See Webhooks for the subscription flow and the 19 notification types.


Terms

Prefix: /v1/terms. Record and check Terms of Service acceptance. The accepting IP is hashed (SHA-256), never stored raw.

Accept terms

POST /v1/terms/accept

Body fieldTypeDescription
wallet_addressstringAccepting wallet.
terms_versionstringDefaults to 0.1.
sourcestringe.g. mobile, web. Default web.
platformstringe.g. ios, android, website.
app_versionstringOptional client version.
{ "success": true, "terms_version": "0.1", "accepted_at": "2026-04-01T10:00:00Z" }

Get terms status

GET /v1/terms/status/:wallet

{ "accepted": true, "latest": { "terms_version": "0.1", "accepted_at": "2026-04-01T10:00:00Z", "platform": "ios" } }

Waitlist

Prefix: /v1/waitlist. Public beta waitlist. Signup is protected by Cloudflare Turnstile.

Join

POST /v1/waitlist/join

Body fieldTypeDescription
cf_tokenstringCloudflare Turnstile token (required).
wallet_addressstringWallet (wallet or email required).
emailstringEmail.
discord_handle, twitter_handlestringOptional socials.
has_seeker, holds_skrbooleanPriority signals.
referral_codestringOptional referral.
{ "success": true, "referral_code": "MGMA-7K2", "priority_score": 25 }

A duplicate signup returns { "success": true, "already_registered": true, … }. Human verification failure returns 400 TURNSTILE_FAILED.

Stats

GET /v1/waitlist/stats

{ "total": 18342 }

NFT

Prefix: /v1/nft. Tier NFTs map a wallet to a Conviction tier. Collections: MLAVA (Flare), MGNSS (Volcanic), MSPEC (Magma).

Verify ownership

POST /v1/nft/verify

Verifies on-chain ownership (Helius DAS), updates the wallet's tier.

{ "wallet_address": "7xKX…9fПb", "mint_address": "Mint…" }
{ "success": true, "wallet_address": "7xKX…9fПb", "mint_address": "Mint…", "tier": "flare", "conviction_multiplier": 1.25, "narrative_score": 0 }

Ownership that can't be verified returns 403.

Mint (prepare / confirm)

POST AUTH /v1/nft/mint

Prepares a Metaplex Core mint. Body: { wallet_address, collection, recipient_wallet? } where collectionmlava | mgnss | mspec.

{
"ok": true,
"collection": "mlava",
"tier": "flare",
"recipient_wallet": "7xKX…9fПb",
"collection_address": "Coll…",
"metadata": { "name": "MAGMA MLAVA", "symbol": "MLAVA", "uri": "https://metadata.magmaprotocol.xyz/nft/mlava/metadata.json" },
"status": "ready_to_mint"
}

Errors: 503 collection_not_deployed, 409 already_minted.

POST AUTH /v1/nft/mint/confirm

Records the confirmed mint and sets the wallet tier. Body: { wallet_address, mint_address, collection, tx_signature? }.

Read & webhooks

EndpointMethodPurpose
/v1/nft/wallet/:walletGETFull NFT ownership state for a wallet.
/v1/nft/score/:mintAddressGETCurrent narrative score for a mint (for marketplaces).
/v1/nft/webhook/heliusPOSTHelius webhook for transfer events. Requires x-webhook-secret.
/v1/nft/webhook/transferPOSTMLAVA/MGNSS transfer webhook. Requires x-webhook-secret.

Shield

Prefix: /v1/shield. Shield is MAGMA's protocol-cover layer — back coverage on a DeFi protocol and earn yield, with payouts on a verified FALSE (exploit) resolution. It also exposes abuse-probe logging used by gated surfaces.

Read & participate

EndpointMethodPurpose
/v1/shield/protocolsGETCovered protocols and current scores.
/v1/shield/protocols/:idGETOne protocol's detail.
/v1/shield/protocols/:id/score-historyGETScore history.
/v1/shield/protocols/:id/oracle-verdictsGETOracle verdicts.
/v1/shield/protocols/:id/rulesGETCoverage rules (also …/rules.pdf).
/v1/shield/apysGETShield coverage APYs.
/v1/shield/leaderboardGETCoverage backer leaderboard.
/v1/shield/backPOST AUTHBack protocol coverage.
/v1/shield/positions/:walletGETA wallet's coverage positions.
/v1/shield/build-claim-txPOST AUTHBuild a claim transaction.
/v1/shield/terms-ackPOSTAcknowledge Shield terms (…/terms-ack/:wallet to read).
/v1/shield/partner-applyPOSTApply as a partner protocol.
/v1/shield/portal/accessGETPartner portal access (?wallet=).

Abuse-probe logging

POST /v1/shield/probe-log

Logs a suspicious access attempt (called client-side on gated pages).

{ "ip_hash": "sha256_hex", "path": "/shield", "method": "GATE_ATTEMPT", "user_agent": "Mozilla/5.0…" }

GET AUTH /v1/shield/blocked — list blocked IP hashes. Admin auth required.

DELETE AUTH /v1/shield/blocked/:ip_hash — unblock a flagged IP hash. Admin auth required.


Binary Markets

Prefix: /v1/binary. The YES/NO binary-markets REST surface is scaffolded and gated — every /v1/binary/* route returns 503 (coming post-TGE).

Not yet live

The binary-markets concept ("back against narratives / the short side") is being delivered on-chain first. GET /v1/binary/status returns { "feature": "coming_soon" }; integrate against the on-chain program until these endpoints ship. Full program and SDK details are in Binary Markets — Program & API.

Native market creation is fee-gated

POST /v1/markets (MAGMA-native binary-market creation, distinct from the gated /v1/binary/* surface) now requires an anti-spam fee — BINARY_MARKET_FEE_SOL (defaults to the ~5 SOL narrative publish fee) — paid via a verified treasury fee-payment tx, alongside a Cloudflare Turnstile token (cf_token) and the creator's signature. Previously this path was ungated. Reject codes: 400 TURNSTILE_FAILED, 400 market_fee_missing_treasury, 401 invalid_signature. See Program & API → market creation.


System

Prefix: /v1/system. Operational status probe.

Get status

GET /v1/system/status

Reports overall API/operational status. Use it for liveness and a basic health signal.

curl 'https://api.magmaprotocol.xyz/v1/system/status'

See also

  • Agents API — machine-readable feed and automation endpoints.
  • Tiers — access tiers and elevated-access requests.
  • TypeScript SDK — typed client over this reference.