Quickstart
This page shows how to run Vela preflight checks in a Next.js server route and call AI SDK streamText() only when execution is allowed. The key point is that blocked / deny paths do not call the model runtime, and only the allow path uses the relay-backed model.
1. Packages
Section titled “1. Packages”pnpm add @vel4ai/sdk @vel4ai/ai-sdk ai@vel4ai/sdk is required. @vel4ai/ai-sdk is an optional adapter that bundles the provider and callbacks for AI SDK streamText().
2. Environment Variables
Section titled “2. Environment Variables”VELA_APP_ID=app_xxxVELA_APP_TOKEN=vela_sk_xxx# Only when using a local or preview APIVELA_BASE_URL=http://localhost:4000Do not make VELA_CUSTOMER_TENANT_ID and VELA_DELEGATION_ID required production environment variables. Resolve execution scope from the Hosted Connect return URL, database, session, or request body.
3. Route Handler
Section titled “3. Route Handler”import { createVelaOpenAI } from "@vel4ai/ai-sdk";import { createVelaClientFromEnvironment, createVelaEnvironmentDiagnosticsResponse, createVelaErrorResponse, createVelaIntegration, getVelaEnvironmentDiagnostics, resolveVelaExecutionScope,} from "@vel4ai/sdk";import { streamText } from "ai";
declare const process: { env: Record<string, string | undefined> };declare function toModelMessages(messages: unknown): Promise<unknown[]>;
const CHAT_ESTIMATED_COST_USD = 0.05;
export async function POST(req: Request): Promise<Response> { const environment = getVelaEnvironmentDiagnostics({ env: process.env });
if (!environment.ok) { return createVelaEnvironmentDiagnosticsResponse(environment); }
try { const body = (await req.json()) as { messages?: unknown; vela?: unknown }; const executionScope = resolveVelaExecutionScope(body.vela);
if (!executionScope) { return Response.json( { error: "Vela execution scope is missing." }, { status: 400 }, ); }
const client = createVelaClientFromEnvironment({ env: process.env }); const vela = createVelaIntegration({ client, executionScope }); const prepared = await vela.prepareExecutionWithResponse({ estimatedCostUsd: CHAT_ESTIMATED_COST_USD, });
if (prepared.outcome !== "allow") { return prepared.response; }
const result = streamText( { model: createVelaOpenAI(prepared).model, messages: await toModelMessages(body.messages), }, );
return result.toUIMessageStreamResponse(); } catch (error) { return createVelaErrorResponse(error, { fallbackMessage: "Vela chat failed unexpectedly.", }); }}4. Implementation Checks
Section titled “4. Implementation Checks”- Return missing env before reading the request body.
- Return 400 for requests without execution scope.
- Return
prepared.responseunchanged whenprepared.outcome !== "allow". - Call
streamText()only afterallow. - Do not call app-side report helpers after using the Vela-managed relay; the relay records execution results.