So you wanna master Solana Actions? Awesome choice. These things are game changers - they're basically magic links that let people sign transactions right from Twitter, Discord, anywhere. No dApps, no clunky interfaces. Just paste a link, wallet pops up, done. I've built a bunch and honestly, once you get the flow, it's stupid simple.
The core? Two endpoints. GET gives metadata (what's this action do?). POST spits out a signable transaction. That's it. Wallets like Phantom handle the rest. Sound familiar? It's like a REST API but for blockchain txns.
Okay, grab your terminal. We're doing Next.js app router cuz it's dead easy and handles the API routes perfectly. If you're not a Next.js fan, whatever, but this is what I always use.
cd solana actions demoNow the fun part. In your app/api/actions folder, make a route.ts. This is your Action's brain. Every Action lives at a URL like yourdomain.com/api/actions/memo.
Memoprogram? Yeah, writes a message on chain. Costs like 0.000005 SOL in fees. Perfect first test.
Here's the code. Copy paste this into app/api/actions/memo/route.ts. I'll explain after.
Whoa, slow down. What just happened? GET returns this JSON that wallets parse into pretty buttons. POST gets the user's wallet address, builds a txn, hands it back. Boom.
Pro tip: That ACTIONSCORSHEADERS? Magic. Wallets need it or they 403 on you. Always include.
Run npm run dev. Hit http://localhost:3000/api/actions/memo in browser. See JSON? Good.
Now the real test. Go to dial.to/?action=solana action:http://localhost:3000/api/actions/memo. Wallet should pop! Click, sign, check Solscan.devnet. Memo's there. I usually freak out first time it works.
Problem? Brave Shields kill it. Turn 'em off. Or use Chrome.
Memos are cute. Let's do swaps. USDC → SOL, dynamic amounts. This is where it gets juicy.
First, add Jupiter SDK: npm i @jup ag/api.
New file: app/api/actions/swap/route.ts. Here's the goods:
Update your GET to have swap params:
typescript parameters: [{ name: "amount", label: "USDC Amount", type: "number", required: true, }]Test URL: dial.to/?action=solana action:http://localhost:3000/api/actions/swap?amount=1. Watch it quote live Jupiter prices. Sign. Swapped. Fees? ~0.000005 SOL + Jupiter's tiny cut.
ACTIONSCORSHEADERS on EVERY response.Want multi step? Like approve → swap → tip? Use links.next in POST response.
In POST, after success:
typescript const payload = await createPostResponse({ fields: { transaction }, links: { next: [{ type: "action", href: "/api/actions/thankyou", // Next action label: "Get Thank You NFT" }] } });Users chain through your flow. Wild.
| Platform | Command | Gotchas |
|---|---|---|
| Vercel | vercel --prod | Free tier perfect. Edge runtime ftw. |
| Helius Flares | Special CLI | Built for Actions. Auto CDN. |
| Cloudflare Workers | wrangler deploy | Cheapest. Global edge. |
I usually Vercel. vercel.json with { "functions": { "*.ts": { "runtime": "edge" } } }. Done.
Live URL: https://your vercel.app/api/actions/memo. Share on Twitter. People click, wallets open. Viral.
Actions shine with inputs. Types?
options: [{label: "1 SOL", value: "1000000000"}]Example - token selector:
typescript parameters: [{ name: "token", label: "From Token", type: "select", options: [ { label: "USDC", value: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }, { label: "SOL", value: "So11111111111111111111111111111111111111112" } ] }]URL becomes ?token=EPjFW..&amount=1. POST reads req.url.searchParams. Clean.
Don't be dumb. Rate limits. Input validation. Rate limits with Upstash Redis. Check user balance before big swaps.
In POST:
typescript // Pseudo rate limit const ip = req.headers.get('x forwarded for'); if (await redis.get(rate:${ip}) > 10) throw new Error('Chill'); // Balance check const balance = await connection.getBalance(user); if (balance < amount 1e9 1.1) throw new Error('Low balance');Errors? Return { error: "Friendly message" } in JSON. Wallets show it nicely.
Twitter? Paste Action URL. Discord? Same. Farcaster? Native. Even embed in websites: <a href="solana action:YOUR_URL">Swap</a>.
Why does this matter? Zero UX friction. Your token launch? One link. Done. I've seen projects 10x usage just from Blinks.
Now build vaults like Meteora. Deposit/withdraw. Use their SDKs. Same pattern:
Fees always ~0.000005 SOL base + program fees. Predictable.
In my experience, start simple (memo), add swaps, then complex DeFi. You'll be shipping Actions like crazy.