{"openapi":"3.1.0","info":{"title":"FreedFinance API","version":"4.0.0","description":"Freed Finance — Institutional-grade DeFi API.\n\nCovers **Auth**, **Portfolio**, **Transfer**, **Swap** (Relay.link), **Fees** estimation, **AI Agent** chat, **KYC**, and **Token Sale** domains.\n\nAll authenticated endpoints require an active session established via SIWE or Turnkey OAuth.\n\n**Rate Limiting**: All endpoints are rate-limited. Exceeding the limit returns `429 Too Many Requests`.\n\n**Response Format**: All endpoints return `{ success, data?, error? }` unless otherwise noted.","contact":{"name":"FreedFinance Engineering","url":"https://freed.finance"},"license":{"name":"Proprietary"}},"paths":{"/api/agent/market-snapshot":{"get":{"tags":["Oracle"],"summary":"Aggregated crypto market snapshot (machine-payable)","operationId":"getAgentMarketSnapshot","description":"Global market aggregates and the Fear & Greed index for autonomous agents. Payable per request over MPP (Machine Payments Protocol) on the Tempo rail — no account or API key required. Unavailable upstream data is returned as `null` with `degraded: true`, never as a synthetic value.","x-payment-info":{"offers":[{"intent":"charge","method":"tempo","amount":"5000","currency":"0x20C0000000000000000000000000000000000000","description":"Per-request market snapshot ($0.005)"}]},"responses":{"200":{"description":"Market snapshot","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"global":{"type":"object","nullable":true},"sentiment":{"type":"object","nullable":true},"degraded":{"type":"boolean"},"asOf":{"type":"string","format":"date-time"}}}}}}}},"402":{"description":"Payment required. The MPP challenge in the `WWW-Authenticate: Payment` header is authoritative; see x-payment-info for advertised terms."},"503":{"description":"Payment rail unconfigured — metered data withheld"}}}},"/api/oracle/dashboard":{"get":{"tags":["Oracle"],"summary":"Get unified token analytics dashboard","operationId":"getOracleDashboard","description":"Returns aggregated price, OHLCV candles, technical indicators, market data, and on-chain liquidity depth in a single highly-optimized API call.","parameters":[{"name":"token","in":"query","required":true,"schema":{"$ref":"#/components/schemas/WalletAddress"},"description":"Token contract address"},{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"},"description":"Network ID (e.g., 1, 137, 42161, 8453)"},{"name":"timeframe","in":"query","schema":{"type":"string","enum":["1m","5m","15m","1h","4h","12h","1d"],"default":"1h"},"description":"OHLCV candle timeframe"},{"name":"coinId","in":"query","schema":{"type":"string"},"description":"Optional CoinGecko ID for exact market data (e.g., 'ethereum')"}],"responses":{"200":{"description":"Dashboard analytics data","content":{"application/json":{"schema":{"type":"object","properties":{"price":{"type":"object"},"candles":{"type":"array","items":{"type":"object"}},"indicators":{"type":"object"},"fearGreed":{"type":"object"},"market":{"type":"object"},"liquidity":{"type":"object"},"lending":{"type":"object"},"cache":{"type":"object"}}}}}},"400":{"description":"Missing required parameters"},"404":{"description":"No liquidity pool found for token"},"429":{"description":"Oracle upstream rate limit exhausted"}}}},"/api/health":{"get":{"tags":["Health"],"summary":"Service health check","operationId":"getHealth","description":"Returns database connectivity, uptime, and latency.","responses":{"200":{"description":"Health status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/auth/gate":{"post":{"tags":["Auth"],"summary":"Password gate verification","operationId":"verifyGate","description":"Validates the master password for protected pages. Sets authentication cookies on success.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["password"],"properties":{"password":{"type":"string"}}}}}},"responses":{"200":{"description":"Authentication successful","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"400":{"description":"Password missing"},"401":{"description":"Invalid password"}}}},"/api/auth/turnkey":{"get":{"tags":["Auth"],"summary":"Check Turnkey session status","operationId":"getTurnkeySession","description":"Returns current Turnkey authentication state. Sessions expire after 12 hours.","responses":{"200":{"description":"Session status","content":{"application/json":{"schema":{"type":"object","properties":{"authenticated":{"type":"boolean"},"address":{"$ref":"#/components/schemas/WalletAddress"},"provider":{"type":"string","enum":["turnkey"]},"turnkeyUserId":{"type":"string","nullable":true}}}}}}}},"post":{"tags":["Auth"],"summary":"Establish Turnkey session","operationId":"createTurnkeySession","description":"Creates an authenticated session for a Turnkey-verified user. Auto-registers user if needed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["address"],"properties":{"address":{"$ref":"#/components/schemas/WalletAddress"},"turnkeyUserId":{"type":"string","format":"uuid","description":"Turnkey user ID for verification"}}}}}},"responses":{"200":{"description":"Session established","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"address":{"type":"string"},"provider":{"type":"string"}}}}}},"400":{"description":"Invalid input"},"429":{"description":"Rate limit exceeded"}}}},"/api/siwe":{"get":{"tags":["SIWE"],"summary":"SIWE operations (nonce, status, session)","operationId":"getSiwe","description":"**action=nonce**: Generate cryptographic nonce for SIWE.\n\n**action=status&wallet=0x…**: Check SIWE verification status.\n\n**No params**: Return current session with user profile.","parameters":[{"name":"action","in":"query","schema":{"type":"string","enum":["nonce","status","session"]}},{"name":"wallet","in":"query","schema":{"$ref":"#/components/schemas/WalletAddress"},"description":"Required when action=status"}],"responses":{"200":{"description":"Nonce, session data, or verification status"}}},"post":{"tags":["SIWE"],"summary":"Verify SIWE signature or logout","operationId":"postSiwe","description":"**action=verify**: Verify a signed SIWE message. Creates session and auto-registers user.\n\n**action=logout**: Destroys current session.","parameters":[{"name":"action","in":"query","required":true,"schema":{"type":"string","enum":["verify","logout"]}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"EIP-4361 SIWE message string"},"signature":{"type":"string","description":"Wallet signature of the message"}}}}}},"responses":{"200":{"description":"Verification result `{ ok: true }`"},"400":{"description":"Missing message or unknown action"},"401":{"description":"Invalid signature or replay attack"}}}},"/api/user":{"get":{"tags":["User"],"summary":"Get user profile","operationId":"getUser","description":"Returns full profile for authenticated user, or public profile if `wallet` query param is provided.","parameters":[{"name":"wallet","in":"query","schema":{"$ref":"#/components/schemas/WalletAddress"},"description":"Optional — returns public profile for this wallet"}],"security":[{"cookieSession":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"User profile","content":{"application/json":{"schema":{"type":"object","properties":{"authenticated":{"type":"boolean"},"wallet":{"type":"string"},"profileComplete":{"type":"boolean"},"profile":{"$ref":"#/components/schemas/UserProfile"}}}}}},"401":{"description":"Not authenticated (when no wallet param)"}}},"post":{"tags":["User"],"summary":"Register new user","operationId":"registerUser","description":"Creates a new user with a unique referral code. Idempotent — returns existing user if already registered.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["wallet"],"properties":{"wallet":{"$ref":"#/components/schemas/WalletAddress"},"email":{"type":"string","format":"email"},"referralCode":{"type":"string","description":"Referral code of the inviting user"}}}}}},"responses":{"200":{"description":"User registered or already exists"},"400":{"description":"Invalid input"},"429":{"description":"Rate limit exceeded"}}},"patch":{"tags":["User"],"summary":"Update user profile","operationId":"updateUser","description":"Updates profile fields for the authenticated user. Tracks changes in profile history for compliance.","security":[{"cookieSession":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string","minLength":3,"maxLength":32,"pattern":"^[a-zA-Z0-9_]*$"},"email":{"type":"string","format":"email"},"name":{"type":"string","maxLength":255},"phone":{"type":"string","maxLength":20},"notifyAml":{"type":"boolean"},"notifyVesting":{"type":"boolean"},"notifyUpdates":{"type":"boolean"},"referralDisclaimerAccepted":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Profile updated"},"400":{"description":"Invalid input"},"401":{"description":"Not authenticated"},"409":{"description":"Username or email already taken"}}}},"/api/user/preferences":{"get":{"tags":["User"],"summary":"Get user preferences","operationId":"getUserPreferences","security":[{"cookieSession":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"User preferences"}}},"post":{"tags":["User"],"summary":"Update swap panel preferences","operationId":"updateUserPreferences","security":[{"cookieSession":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["swapPreferences"],"properties":{"swapPreferences":{"type":"object","properties":{"showCharts":{"type":"boolean"},"showMultiQuoter":{"type":"boolean"},"showAdvancedRouting":{"type":"boolean"},"preferredProvider":{"type":"string","maxLength":50},"countryCode":{"type":"string","maxLength":10}}}}}}}},"responses":{"200":{"description":"Preferences updated"},"400":{"description":"Validation error"}}}},"/api/user/dashboard-preferences":{"get":{"tags":["User"],"summary":"Get dashboard layout preferences","operationId":"getDashboardPreferences","security":[{"cookieSession":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"Dashboard preferences"}}},"post":{"tags":["User"],"summary":"Update dashboard preferences","operationId":"updateDashboardPreferences","security":[{"cookieSession":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["preferences"],"properties":{"preferences":{"type":"object","properties":{"sidebarEnabled":{"type":"boolean"},"sidebarCollapsed":{"type":"boolean"},"theme":{"type":"string","maxLength":20},"showCharts":{"type":"boolean"},"showMultiQuoter":{"type":"boolean"}}}}}}}},"responses":{"200":{"description":"Dashboard preferences updated"},"400":{"description":"Validation error"}}}},"/api/user/wallets":{"get":{"tags":["User"],"summary":"Get user wallet addresses","operationId":"getUserWallets","security":[{"cookieSession":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"Wallet list"}}},"post":{"tags":["User"],"summary":"Add wallet to user profile","operationId":"addUserWallet","security":[{"cookieSession":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["wallet"],"properties":{"wallet":{"type":"object","required":["chain","address"],"properties":{"chain":{"type":"string","enum":["evm","sol","btc"]},"address":{"type":"string","minLength":1,"maxLength":100},"label":{"type":"string","maxLength":100},"isTurnkey":{"type":"boolean"},"turnkeyWalletId":{"type":"string","maxLength":100},"isPrimary":{"type":"boolean"}}}}}}}},"responses":{"200":{"description":"Wallet added"},"400":{"description":"Validation error"},"409":{"description":"Wallet already exists"}}},"delete":{"tags":["User"],"summary":"Remove wallet from user profile","operationId":"deleteUserWallet","security":[{"cookieSession":[]},{"bearerAuth":[]}],"parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string","pattern":"^\\d+$"},"description":"Wallet record ID"}],"responses":{"200":{"description":"Wallet removed"},"404":{"description":"Wallet not found"}}}},"/api/kyc/session":{"get":{"tags":["KYC"],"summary":"Check KYC status","operationId":"getKycSession","description":"Returns KYC status, tier, and verification URL if applicable. Read-only — does not create sessions.\n\nIncludes self-healing: automatically syncs status from KYC provider if webhook was missed.","parameters":[{"name":"wallet","in":"query","required":true,"schema":{"$ref":"#/components/schemas/WalletAddress"}},{"name":"readonly","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"KYC status","content":{"application/json":{"schema":{"type":"object","properties":{"wallet":{"type":"string"},"kycStatus":{"type":"string","enum":["none","pending","approved","rejected"]},"kycTier":{"$ref":"#/components/schemas/KycTier"},"tierName":{"type":"string"},"maxAllowed":{"type":"string"},"isBlocked":{"type":"boolean"},"canBuy":{"type":"boolean"},"verificationUrl":{"type":"string","nullable":true},"needsSessionCreation":{"type":"boolean"}}}}}},"400":{"description":"Invalid wallet format"}}},"post":{"tags":["KYC"],"summary":"Start KYC verification session","operationId":"createKycSession","description":"Creates a new KYC verification session for the specified tier.\n\n**TIER_1**: Basic identity verification (max $999.99)\n\n**TIER_2**: Enhanced KYC + AML + Proof of Address (max $9,999.99)\n\n**TIER_3**: Returns email contact for accredited investor flow","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["wallet"],"properties":{"wallet":{"$ref":"#/components/schemas/WalletAddress"},"callbackUrl":{"type":"string","format":"uri"},"requestedTier":{"$ref":"#/components/schemas/KycTier"}}}}}},"responses":{"200":{"description":"Verification session created with URL"},"400":{"description":"Invalid input"},"429":{"description":"Rate limit exceeded"}}}},"/api/kyc/link-session":{"post":{"tags":["KYC"],"summary":"Link KYC session to wallet","operationId":"linkKycSession","responses":{"200":{"description":"Session linked"}}}},"/api/kyc/upgrade-url":{"get":{"tags":["KYC"],"summary":"Get KYC tier upgrade URL","operationId":"getKycUpgradeUrl","parameters":[{"name":"wallet","in":"query","required":true,"schema":{"$ref":"#/components/schemas/WalletAddress"}},{"name":"tier","in":"query","required":true,"schema":{"$ref":"#/components/schemas/KycTier"}}],"responses":{"200":{"description":"Upgrade URL"}}}},"/api/kyc/webhook":{"post":{"tags":["KYC"],"summary":"KYC provider webhook","operationId":"kycWebhook","description":"Receives verification results from the KYC provider. Authenticated via webhook secret.","responses":{"200":{"description":"Webhook processed"},"401":{"description":"Invalid webhook secret"}}}},"/api/sale/authorize":{"get":{"tags":["Sale"],"summary":"Sale endpoint info","operationId":"getSaleAuthorizeInfo","description":"Returns information about the sale authorization endpoint, including tier limits.","responses":{"200":{"description":"Sale endpoint metadata"}}},"post":{"tags":["Sale"],"summary":"Authorize token purchase","operationId":"authorizePurchase","description":"Validates eligibility (KYC, geo-restrictions, AML) and returns an EIP-712 signature for the smart contract `buy()` function.\n\n**Requirements**: Approved KYC, accepted terms, non-blocked region.\n\n**Min contribution**: $100 USDC/USDT\n\n**Signature validity**: 15 minutes","security":[{"cookieSession":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["wallet","amount","paymentToken"],"properties":{"wallet":{"$ref":"#/components/schemas/WalletAddress"},"amount":{"type":"string","pattern":"^\\d+$","description":"Amount in smallest unit (6 decimals)"},"paymentToken":{"$ref":"#/components/schemas/WalletAddress"},"referrer":{"type":"string","description":"Referrer wallet address (optional)"}}}}}},"responses":{"200":{"description":"Purchase authorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/PurchaseAuthorization"}}}}}},"400":{"description":"Amount below minimum or exceeds tier limit"},"403":{"description":"KYC required, region blocked, terms not accepted, or AML failed"},"404":{"description":"User not registered"},"503":{"description":"RPC connection failed"}}}},"/api/sale/authorize-nft":{"post":{"tags":["Sale"],"summary":"Authorize NFT mint","operationId":"authorizeNftMint","description":"EIP-712 authorization for Genesis NFT minting. Returns signed purchase params for on-chain `buyNft()`.","security":[{"cookieSession":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NftAuthorizeRequest"}}}},"responses":{"200":{"description":"NFT mint authorized with EIP-712 signature"},"400":{"description":"Self-referral blocked or validation error"},"403":{"description":"Geo-blocked or not eligible"},"503":{"description":"Server misconfigured (missing env vars)"}}}},"/api/sale/history":{"get":{"tags":["Sale"],"summary":"Get purchase history","operationId":"getSaleHistory","parameters":[{"name":"wallet","in":"query","required":true,"schema":{"$ref":"#/components/schemas/WalletAddress"}}],"responses":{"200":{"description":"Purchase history"}}}},"/api/sale/status":{"get":{"tags":["Sale"],"summary":"Get sale status","operationId":"getSaleStatus","description":"Returns current sale phase, tokens sold, and price info from the smart contract.","responses":{"200":{"description":"Sale status"}}}},"/api/transfer/prepare":{"post":{"tags":["Transfer"],"summary":"Prepare token transfer","operationId":"prepareTransfer","description":"Validates addresses, estimates gas, and returns transaction parameters for client-side signing.\n\n**Non-custodial**: Server never holds private keys. User signs client-side.","security":[{"cookieSession":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferPrepareRequest"}}}},"responses":{"200":{"description":"Transfer prepared","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"gasEstimate":{"type":"string"},"gasPrice":{"type":"string"},"feeWei":{"type":"string"},"gasUSD":{"type":"number"},"nonce":{"type":"integer"},"ready":{"type":"boolean"},"feeQuote":{"$ref":"#/components/schemas/FeeQuote","description":"HMAC-signed fee quote for gasless execution (null if unsupported chain)"},"amountAfterFee":{"type":"string","nullable":true,"description":"Amount minus fee in smallest unit (only for stablecoin transfers)"},"treasury":{"$ref":"#/components/schemas/WalletAddress","description":"Treasury multisig address for fee collection"},"sponsor":{"type":"string","example":"gelato","description":"Gas sponsorship provider"},"gasless":{"type":"boolean","description":"Whether the transaction is gasless (sponsored)"}}}}}},"400":{"description":"Insufficient balance or unsupported chain"}}}},"/api/transfer/execute":{"post":{"tags":["Transfer"],"summary":"Broadcast signed transaction","operationId":"executeTransfer","description":"Broadcasts a client-signed raw transaction to the network.\n\n**Non-custodial**: Server only relays — cannot access funds.","security":[{"cookieSession":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferExecuteRequest"}}}},"responses":{"200":{"description":"Transaction broadcast","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"hash":{"type":"string"},"chainId":{"type":"integer"},"status":{"type":"string","enum":["pending"]}}}}}},"400":{"description":"Nonce too low, insufficient funds, or gas too low"},"401":{"description":"Not authenticated"}}}},"/api/portfolio/aggregate":{"get":{"tags":["Portfolio"],"summary":"Aggregate multi-chain portfolio","operationId":"getPortfolioAggregate","description":"Aggregates EVM token balances across Ethereum, Polygon, Arbitrum, Base, and Optimism with USD valuations.","parameters":[{"name":"address","in":"query","required":true,"schema":{"$ref":"#/components/schemas/WalletAddress"}}],"security":[{"cookieSession":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"Aggregated portfolio with USD values","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"totalUSD":{"type":"number"},"byChain":{"type":"array","items":{"type":"object","properties":{"chainId":{"type":"integer"},"chainName":{"type":"string"},"nativeBalance":{"type":"string"},"nativeBalanceUSD":{"type":"number"},"totalUSD":{"type":"number"},"tokens":{"type":"array","items":{"$ref":"#/components/schemas/Token"}}}}},"topTokens":{"type":"array","items":{"$ref":"#/components/schemas/Token"}},"lastUpdated":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Invalid address"}}}},"/api/portfolio/bitcoin":{"get":{"tags":["Portfolio"],"summary":"Get Bitcoin portfolio","operationId":"getBitcoinPortfolio","parameters":[{"name":"address","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Bitcoin balance & UTXOs"}}}},"/api/portfolio/solana":{"get":{"tags":["Portfolio"],"summary":"Get Solana portfolio","operationId":"getSolanaPortfolio","parameters":[{"name":"address","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Solana token balances"}}}},"/api/portfolio/history":{"get":{"tags":["Portfolio"],"summary":"Get portfolio value history","operationId":"getPortfolioHistory","parameters":[{"name":"address","in":"query","required":true,"schema":{"$ref":"#/components/schemas/WalletAddress"}}],"responses":{"200":{"description":"Historical portfolio values"}}}},"/api/tokens/list":{"get":{"tags":["Tokens"],"summary":"Get token list","operationId":"getTokenList","description":"Fetches cached multi-chain token lists from DefiLlama. Supports search and chain filtering.","parameters":[{"name":"chainId","in":"query","schema":{"type":"string"},"description":"Chain ID (1, 137, etc.) or 'solana'"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by symbol or name"},{"name":"limit","in":"query","schema":{"type":"integer","default":100},"description":"Max results"},{"name":"refresh","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Force cache refresh"}],"responses":{"200":{"description":"Token list","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"tokens":{"type":"array","items":{"$ref":"#/components/schemas/Token"}},"count":{"type":"integer"}}}}}}}}},"/api/tokens/prices":{"get":{"tags":["Tokens"],"summary":"Get token prices","operationId":"getTokenPrices","description":"Fetches real-time USD prices for tokens.","responses":{"200":{"description":"Token prices"}}}},"/api/market/{path}":{"get":{"tags":["Market"],"summary":"Market data proxy","operationId":"getMarketData","description":"Proxies market data requests. Supports sub-paths for different data types.","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"},"description":"Market data path"}],"responses":{"200":{"description":"Market data"}}}},"/api/geo/permission":{"get":{"tags":["Geo"],"summary":"Check geo-permission","operationId":"getGeoPermission","description":"Returns whether the requesting IP is allowed to access the service based on jurisdiction rules.","responses":{"200":{"description":"Permission status"}}}},"/api/geo/region":{"get":{"tags":["Geo"],"summary":"Detect region","operationId":"getRegion","description":"Returns the detected country code and region for the requesting IP.","responses":{"200":{"description":"Detected region"}}}},"/api/terms":{"get":{"tags":["Terms"],"summary":"Get terms status","operationId":"getTermsStatus","parameters":[{"name":"wallet","in":"query","required":true,"schema":{"$ref":"#/components/schemas/WalletAddress"}}],"responses":{"200":{"description":"Terms acceptance status"}}},"post":{"tags":["Terms"],"summary":"Accept terms","operationId":"acceptTerms","security":[{"cookieSession":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["wallet","termsVersion"],"properties":{"wallet":{"$ref":"#/components/schemas/WalletAddress"},"termsVersion":{"type":"string","example":"v1.0"}}}}}},"responses":{"200":{"description":"Terms accepted"}}}},"/api/referral/resolve":{"get":{"tags":["Referral"],"summary":"Resolve referral code","operationId":"resolveReferral","description":"Looks up a referral code and returns the referrer's wallet address if valid.","parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Referral resolved"},"404":{"description":"Invalid referral code"}}}},"/api/paymaster":{"post":{"tags":["Paymaster"],"summary":"Sponsor gasless transaction","operationId":"sponsorTransaction","description":"Submits a meta-transaction for gasless execution via Gelato Relay (ERC-2771).","security":[{"cookieSession":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"Transaction sponsored"},"401":{"description":"Not authenticated"}}}},"/api/receive/qr":{"get":{"tags":["Receive"],"summary":"Generate receive QR code","operationId":"getReceiveQr","description":"Generates a QR code for receiving funds at the authenticated user's address.","security":[{"cookieSession":[]},{"bearerAuth":[]}],"parameters":[{"name":"address","in":"query","required":true,"schema":{"$ref":"#/components/schemas/WalletAddress"}}],"responses":{"200":{"description":"QR code data"}}}},"/api/transactions/history":{"get":{"tags":["Transactions"],"summary":"Get transaction history","operationId":"getTransactionHistory","description":"Returns transaction history for the authenticated user across all chains.","security":[{"cookieSession":[]},{"bearerAuth":[]}],"parameters":[{"name":"address","in":"query","required":true,"schema":{"$ref":"#/components/schemas/WalletAddress"}}],"responses":{"200":{"description":"Transaction history"}}}},"/api/swap/quote":{"post":{"tags":["Swap"],"summary":"Get cross-chain swap quote","operationId":"getSwapQuote","description":"Returns a Relay.link quote for cross-chain or same-chain token swaps. Includes FREED gas recovery fee.\n\nSupports token symbols (e.g. 'USDC') and contract addresses.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapQuoteRequest"}}}},"responses":{"200":{"description":"Swap quote with fee breakdown","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","description":"Relay.link quote object"},"freedFee":{"$ref":"#/components/schemas/FeeQuote"},"treasury":{"$ref":"#/components/schemas/WalletAddress"},"sponsor":{"type":"string","example":"gelato"},"gasless":{"type":"boolean"}}}}}},"400":{"description":"Unknown token or invalid parameters"}}}},"/api/swap/status":{"get":{"tags":["Swap"],"summary":"Check swap status","operationId":"getSwapStatus","description":"Polls Relay.link for the current status of a cross-chain swap.","parameters":[{"name":"requestId","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":200},"description":"Relay request ID from the quote response"}],"responses":{"200":{"description":"Swap status"},"400":{"description":"Missing requestId"}}}},"/api/fees/estimate":{"get":{"tags":["Fees"],"summary":"Estimate gas recovery fee","operationId":"estimateFee","description":"Returns an HMAC-signed fee quote for sponsored (gasless) transactions. Uses real-time gas prices and oracle data.","parameters":[{"name":"action","in":"query","required":true,"schema":{"type":"string","enum":["transfer","swap","approve","multicall"]}},{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"}},{"name":"tokenAddress","in":"query","schema":{"$ref":"#/components/schemas/WalletAddress"},"description":"Payment token (default: USDC)"},{"name":"isPro","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Fee estimate with HMAC signature","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FeeQuote"}}}}}},"400":{"description":"Invalid parameters"}}}},"/api/chat":{"post":{"tags":["Agent"],"summary":"Send message to FREED AI Agent","operationId":"sendChatMessage","description":"Natural language DeFi assistant. Detects intents (swap, transfer, balance, price, help) and returns structured responses with optional action buttons.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequest"}}}},"responses":{"200":{"description":"Agent response with detected intent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatResponse"}}}},"400":{"description":"Empty message"}}},"get":{"tags":["Agent"],"summary":"Get chat agent capabilities","operationId":"getChatCapabilities","description":"Returns supported intents and example prompts.","responses":{"200":{"description":"Agent capabilities"}}}},"/api/agent/webhook":{"post":{"tags":["Agent"],"summary":"Unified messaging webhook","operationId":"agentWebhook","description":"Receives messages from WhatsApp, Telegram, and other platforms. Normalizes the payload and routes to the Chat Agent.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Platform-specific webhook payload"}}}},"responses":{"200":{"description":"Webhook processed"},"400":{"description":"Unsupported platform or invalid payload"}}},"get":{"tags":["Agent"],"summary":"Webhook verification (challenge)","operationId":"verifyWebhook","description":"Handles platform verification challenges (e.g. WhatsApp verify_token).","parameters":[{"name":"hub.challenge","in":"query","schema":{"type":"string"}},{"name":"hub.verify_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge echo"}}}},"/api/referral/stats":{"get":{"tags":["Referral"],"summary":"Get referral statistics","operationId":"getReferralStats","description":"Returns aggregate referral statistics and recent referral activity for the authenticated user.","security":[{"cookieSession":[]},{"bearerAuth":[]}],"parameters":[{"name":"wallet","in":"query","required":true,"schema":{"$ref":"#/components/schemas/WalletAddress"},"description":"Wallet address of the referrer"}],"responses":{"200":{"description":"Referral statistics","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"totalReferrals":{"type":"integer"},"totalAmountReferred":{"type":"string","description":"Total USDC volume referred"},"totalFreedEarned":{"type":"string","description":"Total FREED earned from referrals"},"totalTokensReferred":{"type":"string","description":"Total tokens referred"},"recentReferrals":{"type":"array","items":{"type":"object","properties":{"wallet":{"type":"string"},"amount":{"type":"string"},"tokens":{"type":"string"},"date":{"type":"string","format":"date-time"}}}}}}}}}}},"400":{"description":"Missing or invalid wallet parameter"}}}},"/api/cron/indexer":{"get":{"tags":["Internal"],"summary":"On-chain event indexer","operationId":"cronIndexer","description":"Vercel Cron Job: indexes Purchase events from the token sale contract and upserts to the database.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Indexing result (events processed)"},"401":{"description":"Invalid CRON_SECRET"}}}},"/api/cron/process-webhooks":{"get":{"tags":["Internal"],"summary":"Webhook queue processor","operationId":"cronProcessWebhooks","description":"Vercel Cron Job: drains SQS webhook queue, processes messages in parallel with failure isolation.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Processing result","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"processed":{"type":"integer"},"failed":{"type":"integer"},"skipped":{"type":"integer"},"durationMs":{"type":"number"},"errors":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"Invalid CRON_SECRET"},"503":{"description":"SQS not configured"}}}},"/api/csp-report":{"post":{"tags":["Internal"],"summary":"CSP violation report endpoint","operationId":"submitCspReport","description":"Receives Content Security Policy violation reports from browsers and forwards to Sentry.","requestBody":{"required":true,"content":{"application/csp-report":{"schema":{"type":"object","properties":{"csp-report":{"type":"object","properties":{"document-uri":{"type":"string"},"violated-directive":{"type":"string"},"blocked-uri":{"type":"string"},"original-policy":{"type":"string"}}}}}}}},"responses":{"200":{"description":"Report received"},"400":{"description":"Invalid report format"}}},"get":{"tags":["Internal"],"summary":"CSP report health check","operationId":"cspReportHealth","responses":{"200":{"description":"Endpoint active"}}}},"/api/mpp/consent":{"get":{"tags":["MPP"],"summary":"Get MPP consent status","operationId":"getMppConsent","description":"Returns the user's MPP (Machine Payment Protocol) consent status, Tempo auto-funding preferences, and spend summary including all-time and 24h totals.","security":[{"cookieSession":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"Consent status, spend stats, and recent payments","content":{"application/json":{"schema":{"type":"object","properties":{"consent":{"type":"object","nullable":true,"properties":{"autoFundEnabled":{"type":"boolean"},"preferredSourceChain":{"type":"string","enum":["arbitrum","base","optimism","polygon","ethereum","solana"]},"tempoAddress":{"type":"string","nullable":true},"cachedTempoBalance":{"type":"string","nullable":true},"balanceUpdatedAt":{"type":"string","format":"date-time","nullable":true},"consentGrantedAt":{"type":"string","format":"date-time","nullable":true}}},"mppEnabled":{"type":"boolean"},"spend":{"type":"object","properties":{"allTime":{"type":"object","properties":{"total":{"type":"number"},"payments":{"type":"integer"}}},"today":{"type":"object","properties":{"total":{"type":"number"},"payments":{"type":"integer"}}}}},"recentPayments":{"type":"array","items":{"type":"object"}}}}}}},"401":{"description":"Not authenticated"}}},"post":{"tags":["MPP"],"summary":"Update MPP consent","operationId":"updateMppConsent","description":"Enable or disable Tempo auto-funding and set the preferred source chain for MPP payments.","security":[{"cookieSession":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"autoFundEnabled":{"type":"boolean","default":false,"description":"Enable Tempo auto-funding for MPP payments"},"preferredSourceChain":{"type":"string","enum":["arbitrum","base","optimism","polygon","ethereum","solana"],"default":"arbitrum","description":"Preferred chain for auto-funding"}}}}}},"responses":{"200":{"description":"Consent updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"consent":{"type":"object","properties":{"autoFundEnabled":{"type":"boolean"},"preferredSourceChain":{"type":"string"},"consentGrantedAt":{"type":"string","format":"date-time","nullable":true}}}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Not authenticated"}}}}},"servers":[{"url":"/","description":"Current environment (paths are absolute from the site root, so MPP clients that do not resolve a server base path still reach the right URL)"}],"x-service-info":{"categories":["data","developer-tools","compute"],"docs":{"homepage":"https://freed.finance","apiReference":"https://freed.finance/api/docs","llms":"https://freed.finance/llms.txt"}},"tags":[{"name":"Health","description":"Service health & readiness"},{"name":"Auth","description":"Authentication (password gate, Turnkey)"},{"name":"SIWE","description":"Sign-In With Ethereum (nonce, verify, session, logout)"},{"name":"User","description":"User profile (CRUD, preferences, wallets)"},{"name":"KYC","description":"KYC verification sessions (3-tier: Light, Enhanced, Accredited)"},{"name":"Sale","description":"Token sale authorization & history"},{"name":"Transfer","description":"Non-custodial token transfers (prepare + broadcast)"},{"name":"Swap","description":"Cross-chain token swaps via Relay.link (quote + status)"},{"name":"Fees","description":"Real-time gas fee estimation with HMAC-signed quotes (Gelato sponsored)"},{"name":"Agent","description":"FREED AI Chat Agent — conversational DeFi assistant with multi-channel support (WhatsApp, Telegram, MCP)"},{"name":"Portfolio","description":"Multi-chain portfolio aggregation"},{"name":"Tokens","description":"Token lists & prices (DefiLlama)"},{"name":"Market","description":"Market data proxy"},{"name":"Geo","description":"Geo-restriction & region detection"},{"name":"Terms","description":"Terms & conditions acceptance"},{"name":"Referral","description":"Referral code resolution & stats"},{"name":"Paymaster","description":"Gasless transaction sponsorship"},{"name":"Receive","description":"QR code generation for receiving funds"},{"name":"Transactions","description":"Transaction history"},{"name":"MPP","description":"Machine Payment Protocol — consent management, spend tracking, and Tempo auto-funding"},{"name":"Oracle","description":"Real-time DeFi market data, technical indicators, liquidity, and TVL"},{"name":"Internal","description":"Internal cron jobs and system endpoints (authenticated via VERCEL_CRON_SECRET)"}],"components":{"securitySchemes":{"cookieSession":{"type":"apiKey","in":"cookie","name":"freed-session","description":"Iron Session cookie set after SIWE verification or Turnkey OAuth."},"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Bearer JWT token for mobile/API clients. Obtain via `/auth/turnkey` or SIWE flow."}},"schemas":{"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Descriptive error message"}},"required":["error"]},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true}},"required":["success"]},"WalletAddress":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","example":"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18","description":"Ethereum address (checksummed or lowercase)"},"UserProfile":{"type":"object","properties":{"id":{"type":"integer"},"username":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"emailVerified":{"type":"boolean"},"name":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"kycStatus":{"type":"string","enum":["none","pending","approved","rejected"]},"siweVerified":{"type":"boolean"},"referralCode":{"type":"string"},"isBlocked":{"type":"boolean"},"countryCode":{"type":"string","nullable":true},"notifyAml":{"type":"boolean"},"notifyVesting":{"type":"boolean"},"notifyUpdates":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}}},"KycTier":{"type":"string","enum":["TIER_1","TIER_2","TIER_3"],"description":"TIER_1: ≤$999.99 | TIER_2: ≤$9,999.99 | TIER_3: Unlimited (accredited)"},"PurchaseAuthorization":{"type":"object","properties":{"buyer":{"$ref":"#/components/schemas/WalletAddress"},"paymentToken":{"$ref":"#/components/schemas/WalletAddress"},"amount":{"type":"string","description":"Amount in token smallest unit (6 decimals for USDC)"},"maxAllowed":{"type":"string"},"isEU":{"type":"boolean","description":"MiCA compliance flag"},"referrer":{"$ref":"#/components/schemas/WalletAddress"},"nonce":{"type":"string"},"deadline":{"type":"string"},"signature":{"type":"string","description":"EIP-712 backend signature"},"tier":{"$ref":"#/components/schemas/KycTier"},"purchaseParams":{"type":"object","description":"Ready-to-use calldata for the smart contract buy() function"}}},"Token":{"type":"object","properties":{"address":{"type":"string"},"symbol":{"type":"string"},"name":{"type":"string"},"decimals":{"type":"integer"},"logoURI":{"type":"string","nullable":true},"chainId":{"type":"integer"}}},"TransferPrepareRequest":{"type":"object","required":["from","to","token","amount","chainId"],"properties":{"from":{"$ref":"#/components/schemas/WalletAddress"},"to":{"$ref":"#/components/schemas/WalletAddress"},"token":{"oneOf":[{"type":"string","const":"native"},{"$ref":"#/components/schemas/WalletAddress"}],"description":"'native' for ETH, or ERC-20 contract address"},"amount":{"type":"string","description":"Amount as BigInt string (smallest unit)"},"chainId":{"type":"integer","description":"1=ETH, 137=Polygon, 42161=Arbitrum, 8453=Base, 10=OP"}}},"TransferExecuteRequest":{"type":"object","required":["signedTx","chainId"],"properties":{"signedTx":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Client-signed raw transaction"},"chainId":{"type":"integer"}}},"HealthResponse":{"type":"object","properties":{"status":{"type":"string","enum":["ok","error"]},"db":{"type":"string","enum":["healthy","unhealthy","unknown"]},"timestamp":{"type":"string","format":"date-time"},"uptime":{"type":"number"},"latency":{"type":"string"},"version":{"type":"string"},"environment":{"type":"string"}}},"SwapQuoteRequest":{"type":"object","required":["userAddress","fromChainId","toChainId","fromToken","toToken","amount"],"properties":{"userAddress":{"$ref":"#/components/schemas/WalletAddress"},"fromChainId":{"type":"integer"},"toChainId":{"type":"integer"},"fromToken":{"type":"string","description":"Token symbol (e.g. 'USDC') or contract address"},"toToken":{"type":"string","description":"Token symbol or contract address"},"amount":{"type":"string","description":"Raw amount in smallest unit"},"tradeType":{"type":"string","enum":["EXACT_INPUT","EXACT_OUTPUT"],"default":"EXACT_INPUT"},"slippageBps":{"type":"integer","minimum":1,"maximum":5000,"default":50,"description":"Slippage in basis points (50 = 0.5%)"},"isPro":{"type":"boolean","default":false,"description":"Genesis NFT holder (reduced fees)"}}},"FeeQuote":{"type":"object","description":"HMAC-signed fee quote for gasless execution","properties":{"fee":{"type":"string","description":"Fee in payment token smallest unit"},"feeUsd":{"type":"number"},"gasCostUsd":{"type":"number"},"markup":{"type":"number"},"signature":{"type":"string","description":"HMAC signature for tamper-proof verification"},"expiresAt":{"type":"string","format":"date-time","description":"Quote expiry (ISO 8601)"}}},"FeeEstimateQuery":{"type":"object","required":["action","chainId"],"properties":{"action":{"type":"string","enum":["transfer","swap","approve","multicall"]},"chainId":{"type":"integer"},"tokenAddress":{"$ref":"#/components/schemas/WalletAddress","description":"Payment token (default: USDC)"},"tokenDecimals":{"type":"integer","minimum":0,"maximum":18,"default":6},"tokenPriceUSD":{"type":"number","default":1},"amount":{"type":"string","description":"Optional BigInt string — returns amountAfterFee"},"isPro":{"type":"string","enum":["true","false"],"description":"Genesis NFT holder tier"}}},"ChatRequest":{"type":"object","required":["message"],"properties":{"message":{"type":"string","minLength":1,"maxLength":2000,"description":"Natural language message"},"wallet":{"$ref":"#/components/schemas/WalletAddress"},"sessionId":{"type":"string"},"channel":{"type":"string","enum":["web","whatsapp","telegram","mcp","api"],"default":"web"},"confirmAction":{"type":"string","description":"Action ID to confirm (from previous response)"}}},"ChatResponse":{"type":"object","properties":{"success":{"type":"boolean"},"response":{"type":"object","properties":{"message":{"type":"string"},"intent":{"type":"string"},"data":{"type":"object"},"suggestions":{"type":"array","items":{"type":"string"}},"actions":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"action":{"type":"string"},"params":{"type":"object"},"destructive":{"type":"boolean"}}}},"requiresConfirmation":{"type":"boolean"},"confirmationPrompt":{"type":"string"}}}}},"NftAuthorizeRequest":{"type":"object","required":["wallet","amount","paymentToken","tokenId"],"properties":{"wallet":{"$ref":"#/components/schemas/WalletAddress"},"amount":{"type":"string","pattern":"^\\d+$","description":"Amount in smallest unit (6 decimals for USDC)"},"paymentToken":{"$ref":"#/components/schemas/WalletAddress"},"tokenId":{"type":"string","pattern":"^\\d+$","description":"Genesis Token ID"},"tierId":{"type":"integer","minimum":1,"maximum":255,"default":1,"description":"V3 multi-tier support"},"referrer":{"$ref":"#/components/schemas/WalletAddress","description":"Referrer wallet (optional, self-referral blocked)"}}}}}}