API

REST API

HTTP endpoints for any language. No SDK needed — just HTTP calls.

Note
Base URL: https://sow-beryl.vercel.app. All endpoints return JSON with { ok: boolean, data: ... } or { ok: false, error: "..." }.

Authentication

Public endpoints (GET /api/plans, GET /api/price, GET /api/auth) require no auth. All other endpoints require one of two methods:

Sign a message with any Solana wallet. No registration, no API keys, no database. Your wallet IS your identity.

auth.ts
typescript
1// 1. Get the message to sign
2const res = await fetch("https://sow-beryl.vercel.app/api/auth")
3const { data } = await res.json()
4// data.message = "Buff API Authentication"
5
6// 2. Sign it with your wallet
7const message = new TextEncoder().encode(data.message)
8const signature = await wallet.signMessage(message)
9const sigBase64 = btoa(String.fromCharCode(...signature))
10
11// 3. Use on any protected endpoint
12fetch("https://sow-beryl.vercel.app/api/roundup", {
13 method: "POST",
14 headers: {
15 "Content-Type": "application/json",
16 "x-wallet": wallet.publicKey.toBase58(),
17 "x-signature": sigBase64,
18 },
19 body: JSON.stringify({ txValueUsd: 27.63, plan: "tree" }),
20})

Method 2: Static API Key

For server-to-server integrations where wallet signing is not practical.

bash
bash
curl -X POST https://sow-beryl.vercel.app/api/roundup \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key" \
-d '{"txValueUsd": 27.63, "plan": "tree"}'

GET /api/auth

Get the authentication message to sign, and instructions.

response.json
typescript
1{
2 "ok": true,
3 "data": {
4 "message": "Buff API Authentication",
5 "instructions": "Sign this message with your Solana wallet..."
6 }
7}

POST /api/auth

Verify your signature works before using protected endpoints.

bash
bash
curl -X POST https://sow-beryl.vercel.app/api/auth \
-H "Content-Type: application/json" \
-d '{"wallet": "YourPubkey...", "signature": "Base64Sig..."}'

Rate Limiting

All API endpoints are rate-limited to 60 requests per minute per IP. Response headers include X-RateLimit-Limit and X-RateLimit-Remaining.

GET /api/plans

List all available plan tiers and defaults.

bash
bash
curl https://your-buff.vercel.app/api/plans
response.json
typescript
1{
2 "ok": true,
3 "data": {
4 "plans": {
5 "seed": { "name": "Seed", "roundToUsd": 0.05, "buffFeePercent": 1.00 },
6 "sprout": { "name": "Sprout", "roundToUsd": 0.10, "buffFeePercent": 0.75 },
7 "tree": { "name": "Tree", "roundToUsd": 0.50, "buffFeePercent": 0.50 },
8 "forest": { "name": "Forest", "roundToUsd": 1.00, "buffFeePercent": 0.25 }
9 },
10 "ceiling": 1.0,
11 "defaultPlan": "sprout",
12 "defaultAsset": "BTC",
13 "defaultThreshold": 5.0,
14 "supportedAssets": ["BTC", "ETH", "SOL", "USDC", "USDT"]
15 }
16}

GET /api/price

Get real-time token prices (cached 30s).

bash
bash
curl https://your-buff.vercel.app/api/price
response.json
typescript
1{
2 "ok": true,
3 "data": {
4 "prices": { "SOL": 88.42, "BTC": 71080, "ETH": 2101.15, "USDC": 1.0, "USDT": 1.0 },
5 "timestamp": 1710000000000
6 }
7}

POST /api/roundup

Calculate the round-up for a transaction value.

FieldTypeRequiredDescription
txValueUsdnumberYesTotal transaction value in USD
planstringNoPlan tier: seed, sprout, tree, forest
roundToUsdnumberNoCustom round-up increment (overrides plan)
ceilingnumberNoMax round-up (default: 1.00)
bash
bash
curl -X POST https://your-buff.vercel.app/api/roundup \
-H "Content-Type: application/json" \
-d '{"txValueUsd": 27.63, "plan": "tree"}'
response.json
typescript
1{
2 "ok": true,
3 "data": {
4 "txValueUsd": 27.63,
5 "roundToUsd": 0.50,
6 "roundedToUsd": 28.00,
7 "roundUpUsd": 0.37,
8 "roundUpSol": 0.004185,
9 "buffFeePercent": 0.50,
10 "buffFeeUsd": 0.00185,
11 "buffFeeSol": 0.0000209,
12 "userInvestmentUsd": 0.36815,
13 "userInvestmentSol": 0.004164,
14 "solPriceUsd": 88.42,
15 "skipped": false,
16 "capped": false
17 }
18}

POST /api/swap/quote

Get a Jupiter swap quote (SOL → target asset).

FieldTypeRequiredDescription
inputLamportsnumberYesAmount of SOL in lamports (1 SOL = 1e9)
targetAssetstringNoBTC, ETH, SOL, USDC, USDT (default: BTC)
slippageBpsnumberNoSlippage in basis points (default: 100 = 1%)
bash
bash
curl -X POST https://your-buff.vercel.app/api/swap/quote \
-H "Content-Type: application/json" \
-d '{"inputLamports": 100000000, "targetAsset": "USDC"}'
response.json
typescript
1{
2 "ok": true,
3 "data": {
4 "inputLamports": 100000000,
5 "inputSol": 0.1,
6 "outputAmount": "8847771",
7 "targetAsset": "USDC",
8 "priceImpact": "0",
9 "route": "Raydium → Orca"
10 }
11}

POST /api/wallet/derive

Derive a Buff wallet public key from a signature. Returns only the public key — never the private key.

bash
bash
curl -X POST https://your-buff.vercel.app/api/wallet/derive \
-H "Content-Type: application/json" \
-d '{"signature":"base64-encoded-signature"}'
response.json
typescript
1{
2 "ok": true,
3 "data": {
4 "publicKey": "A2bBXAg4r8Rb2qFoycqBCsDDDmnDEKD8w1V3VPv1eR5T",
5 "derivationMessage": "Buff Portfolio Wallet v1"
6 }
7}

GET /api/portfolio/:address

Read all token balances and USD values for any Solana wallet.

bash
bash
curl "https://your-buff.vercel.app/api/portfolio/E71R6Ph2sS...?network=devnet"
response.json
typescript
1{
2 "ok": true,
3 "data": {
4 "walletAddress": "E71R6Ph2sS...",
5 "network": "devnet",
6 "balances": [{ "asset": "BTC", "balance": "0.00068", "usdValue": 48.20 }],
7 "totalUsd": 48.20,
8 "pendingSol": 0.004617,
9 "pendingUsd": 0.41,
10 "solPriceUsd": 88.04
11 }
12}

GET /api/accumulator/:address

Check if a wallet has reached the investment threshold.

bash
bash
curl "https://your-buff.vercel.app/api/accumulator/E71R6Ph2sS...?threshold=5&network=devnet"
response.json
typescript
1{
2 "ok": true,
3 "data": {
4 "balanceSol": 0.004617,
5 "balanceUsd": 0.41,
6 "solPriceUsd": 88.04,
7 "thresholdUsd": 5.0,
8 "thresholdReached": false,
9 "remaining": 4.59
10 }
11}

POST /api/swap/execute

Submit a pre-signed transaction to the Solana network. The transaction must already be signed — the API just relays it.

bash
bash
curl -X POST https://your-buff.vercel.app/api/swap/execute \
-H "Content-Type: application/json" \
-d '{"signedTransaction":"base64-encoded-tx","network":"mainnet-beta"}'
response.json
typescript
1{
2 "ok": true,
3 "data": {
4 "txSignature": "4Hkbeas...",
5 "confirmed": true,
6 "network": "mainnet-beta"
7 }
8}