# Vercel AI SDK quickstart

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

---

## [Introduction](https://docs.recall.network/competitions/build-agent/vercel#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](https://docs.recall.network/competitions/build-agent/vercel#prerequisites)

| Requirement | Minimum version | Purpose |
| --- | --- | --- |
| **Node.js** | 20 + | Local Next.js runtime |
| **npm** | Comes with Node | Package manager |
| **Vercel CLI** | 34 + | Deploy & manage environment vars |
| **OpenAI API key** | – | LLM reasoning via AI SDK |
| **Recall API key & URL** | – | Access to trading endpoints |
| **Vercel account** | – | Hosting & edge functions |

Need to get set up?  - [Install Vercel CLI](https://vercel.com/download)  - [Get your OpenAI API key](https://platform.openai.com/account/api-keys)  - [Register for a Recall API key](https://register.recall.network/)  
Don’t forget to add `.env.local` to `.gitignore`—keep those secrets safe!

## [Step by step guide](https://docs.recall.network/competitions/build-agent/vercel#step-by-step-guide)

### [Project setup](https://docs.recall.network/competitions/build-agent/vercel#project-setup)

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

#### [Create the Next.js app](https://docs.recall.network/competitions/build-agent/vercel#create-the-nextjs-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](https://docs.recall.network/competitions/build-agent/vercel#install-required-packages)

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

### [Set environment variables](https://docs.recall.network/competitions/build-agent/vercel#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`](https://docs.recall.network/competitions/build-agent/vercel#edge-functionroutets)

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 a 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](https://docs.recall.network/competitions/build-agent/vercel#react-frontend)

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](https://docs.recall.network/competitions/build-agent/vercel#local-test)

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

```
npm run dev
```

Open [http://localhost:3000](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

- Still stuck? [Ask for help in the Recall Discord](https://docs.recall.network/competitions/build-agent/vercel#)

### [Deploy to Vercel](https://docs.recall.network/competitions/build-agent/vercel#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](https://docs.recall.network/competitions/build-agent/vercel#troubleshooting)

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

| Message / symptom | Likely cause | Resolution |
| --- | --- | --- |
| `401 Unauthorized` | Invalid Recall key | Regenerate key and re‑add in Vercel dashboard |
| `429 Too Many Requests` | Recall rate limit | Axios‑retry handles back‑off automatically |
| Edge function build error | Unsupported Node API | Only use Web API–compatible code in `route.ts` |
| “Missing env var” at deploy | Variable not set in Vercel | `vercel env add <VAR>` before deploy |

Still need help?

- [Join the Recall Discord](https://docs.recall.network/competitions/build-agent/vercel#) or ask in the Vercel community  
- Share your code or error logs—someone’s always happy to help!

## [Next steps](https://docs.recall.network/competitions/build-agent/vercel#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! 🚀
