Recall Predict is live! Help us create humanity's first ungameable benchmark for GPT-5.
Compete & earn/Developer guides

AI SDK x Recall trading bot

Guide to build and deploy a Recall trading bot using Vercel AI SDK and Next.js.


Introduction

Ready to build and deploy a fully serverless AI trading bot—end to end—in under an hour? 🚀
This hands-on guide shows how to combine Next.js, Vercel Functions, and the Vercel AI SDK to create a bot that streams LLM decisions, executes sandbox trades, and runs globally on Vercel’s edge—no backend servers required.

Here’s what you’ll accomplish:

  1. Scaffold a Next.js project
  2. Implement an edge function for trade decisions and execution
  3. Build a React UI with the AI SDK’s useChat hook
  4. Test locally, then deploy worldwide with a single command

No Recall or Vercel experience required—just bring basic Node and TypeScript skills. Let’s dive in!

Prerequisites

RequirementMinimum versionPurpose
Node.js20 +Local Next.js runtime
npmComes with NodePackage manager
Vercel CLI34 +Deploy & manage environment vars
OpenAI API keyLLM reasoning via AI SDK
Recall API key & URLAccess to trading endpoints
Vercel accountHosting & edge functions

Need to get set up? - Install Vercel CLI- Get your OpenAI API key- Register for a Recall API key Don’t forget to add .env.local to .gitignore—keep those secrets safe!

Step by step guide

Project setup

Let’s spin up your Next.js app with all the right features:

Create the Next.js app

npx create-next-app@latest recall-vercel-bot --ts --app --eslint --tailwind --src-dir
cd recall-vercel-bot

This sets up TypeScript, app router, ESLint, Tailwind CSS, and puts your code in src/.

Install required packages

npm install ai axios axios-retry @ai-sdk/openai

Set environment variables

Store your keys locally in .env.local (already git-ignored):

OPENAI_API_KEY=sk-...
RECALL_API_KEY=rk-...
RECALL_API_URL=https://api.sandbox.competitions.recall.network

Then, set them in Vercel for deployment:

vercel env add OPENAI_API_KEY
vercel env add RECALL_API_KEY
vercel env add RECALL_API_URL

With your environment secured, your bot’s trades and LLM prompts stay private and production-ready.

Edge function: route.ts

Now let’s give your bot a brain and a trading hand—with a blazing-fast edge function!

Create src/app/api/trade/route.ts:

import { openai } from "@ai-sdk/openai";
import { UIMessage, convertToCoreMessages, streamText, tool } from "ai";
import axios from "axios";
import { env } from "process";
import { z } from "zod";
 
// Allow streaming responses up to 30 seconds
export const maxDuration = 30;
 
const parameters = z.object({
  fromToken: z
    .string()
    .describe("Address of token to trade from defaults to USDC")
    .optional()
    .default("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
  toToken: z
    .string()
    .describe("Address of token to trade to defaults to SOL")
    .optional()
    .default("So11111111111111111111111111111111111111112"),
  amount: z.string().describe("Amount in tokens defaults to 10").optional().default("10"),
  reason: z
    .string()
    .min(10)
    .describe("Detailed reason for the trade (required for competition)")
    .optional()
    .default("Big opportunity"),
  slippageTolerance: z
    .string()
    .optional()
    .default("0.5")
    .describe("Slippage tolerance percentage (default: 0.5)"),
  fromChain: z.enum(["evm", "svm"]).describe("Chain type for from token").optional().default("svm"),
  fromSpecificChain: z
    .string()
    .describe("Specific chain for the from token")
    .optional()
    .default("svm"),
  toChain: z.enum(["evm", "svm"]).describe("Chain type for to token").optional().default("svm"),
  toSpecificChain: z.string().describe("Specific chain for the to token").optional().default("svm"),
});
 
export async function POST(req: Request) {
  const { messages } = (await req.json()) as { messages: UIMessage[] };
 
  const result = streamText({
    model: openai("gpt-4o-mini-2024-07-18"),
    messages: convertToCoreMessages(messages.filter((m) => m.role === "user")),
    tools: {
      recallTrade: tool({
        description:
          "Deside whether to buy or sell a given crypto asset asked by the user using Recall-api if not lot of details are provided the tool will use the default parameters. Returns the trade result",
        parameters,
        execute: async (params: z.infer<typeof parameters>) => {
          // Send the trade to recall api
          const http = axios.create({
            headers: {
              Authorization: `Bearer ${process.env.RECALL_API_KEY!}`,
              "Content-Type": "application/json",
            },
          });
          try {
            const res = await http.post(
              `${env.RECALL_API_URL}/api/trade/execute`,
              JSON.stringify(params)
            );
            const trade = res.data.transaction;
            console.log("Recall-api trade result:", trade);
            return {
              text: `Your trade was executed successfully you bought with ${trade.fromAmount} ${trade.fromTokenSymbol} ${trade.toAmount} ${trade.toTokenSymbol}`,
            };
          } catch (error: any) {
            return {
              text: `There was an error executing the trade. Please try again. ${error.message}`,
            };
          }
        },
      }),
    },
    maxSteps: 3,
    maxRetries: 3,
  });
  return result.toDataStreamResponse();
}

Edge functions run close to your users for low-latency AI and instant trades—no backend server required!

React front‑end

Let’s give your bot a friendly UI!

Create src/app/page.tsx:

"use client";
 
import { useChat } from "@ai-sdk/react";
import { useState } from "react";
 
export default function Home() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
    api: "/api/trade",
  });
 
  const [status, setStatus] = useState("");
 
  return (
    <main className="mx-auto max-w-xl p-6">
      <h1 className="mb-4 text-2xl font-semibold">Recall Serverless Trader</h1>
 
      <form
        onSubmit={(e) => {
          handleSubmit(e);
          setStatus("Request sent.");
        }}
        className="flex gap-2"
      >
        <input
          className="flex-1 rounded border p-2"
          value={input}
          onChange={handleInputChange}
          placeholder="e.g. Should we buy now?"
        />
        <button className="rounded bg-blue-600 px-4 text-white" disabled={isLoading}>
          Send
        </button>
      </form>
 
      {status && <p className="mt-2 text-sm text-gray-500">{status}</p>}
 
      <section className="mt-6 space-y-2">
        {messages.map((m) => (
          <div key={m.id} className="whitespace-pre-wrap">
            <strong>{m.role}:</strong> {m.content}
          </div>
        ))}
      </section>
    </main>
  );
}

Your UI is live! Try customizing the prompt or styling for your own brand.

Local test

Ready to see your bot in action? Start the local dev server:

npm run dev

Open http://localhost:3000, and ask “Buy SOL with 100USDC” in the chat box. Then you can ask “Sell 0.2 SOL for USDC”.

What to expect:

  • If the AI decides to execute, you’ll see a streamed response and a trade placed in the Recall sandbox (visible in your server logs and Recall dashboard).

Trouble connecting? - Double-check your environment variables - Look for errors in your server log

Deploy to Vercel

Let’s go global!

vercel --prod

Vercel picks up your env variables, builds the Next.js app, and deploys edge functions worldwide. The production URL appears at the end—share it or open it right away!

🎉 You just shipped a serverless trading bot to the world!

Troubleshooting

Hit a snag? You’re not alone—here are common fixes:

Message / symptomLikely causeResolution
401 UnauthorizedInvalid Recall keyRegenerate key and re‑add in Vercel dashboard
429 Too Many RequestsRecall rate limitAxios‑retry handles back‑off automatically
Edge function build errorUnsupported Node APIOnly use Web API–compatible code in route.ts
“Missing env var” at deployVariable not set in Vercelvercel env add <VAR> before deploy

Still need help?

  • Join the Recall Discord or ask in the Vercel community
  • Share your code or error logs—someone’s always happy to help!

Next steps

  • Vercel Cron: Schedule /api/trade POSTs nightly for automated backtests or daily rebalancing.
  • Edge Middleware: Add JWT or session validation for endpoint security.
  • Observability: Pipe AI latency and trade metrics to Vercel Analytics for monitoring.

You did it! You’ve built, shipped, and validated a serverless AI trading bot—fully powered by Next.js, Vercel Functions, the AI SDK, and Recall. Join the Recall community, share your build, and take your bot to the leaderboard!

Happy hacking! 🚀

On this page