Skip to content
'; user_status_content.firstChild.appendChild(avatarContainer); } else { // Placeholder for LoggedOutUserMenu let loggedOutContainer = document.createElement('div'); // if LoggedOutUserMenu fallback let userBtn = document.createElement('button'); userBtn.style.width = "33px"; userBtn.style.height = "33px"; userBtn.style.display = "flex"; userBtn.style.alignItems = "center"; userBtn.style.justifyContent = "center"; userBtn.style.color = "var(--ds-gray-900)"; userBtn.style.border = "1px solid var(--ds-gray-300)"; userBtn.style.borderRadius = "100%"; userBtn.style.cursor = "pointer"; userBtn.style.background = "transparent"; userBtn.style.padding = "0"; // user icon ( from geist) let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('data-testid', 'geist-icon'); svg.setAttribute('height', '16'); svg.setAttribute('stroke-linejoin', 'round'); svg.setAttribute('style', 'color:currentColor'); svg.setAttribute('viewBox', '0 0 16 16'); svg.setAttribute('width', '16'); let path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('fill-rule', 'evenodd'); path.setAttribute('clip-rule', 'evenodd'); path.setAttribute('d', 'M7.75 0C5.95507 0 4.5 1.45507 4.5 3.25V3.75C4.5 5.54493 5.95507 7 7.75 7H8.25C10.0449 7 11.5 5.54493 11.5 3.75V3.25C11.5 1.45507 10.0449 0 8.25 0H7.75ZM6 3.25C6 2.2835 6.7835 1.5 7.75 1.5H8.25C9.2165 1.5 10 2.2835 10 3.25V3.75C10 4.7165 9.2165 5.5 8.25 5.5H7.75C6.7835 5.5 6 4.7165 6 3.75V3.25ZM2.5 14.5V13.1709C3.31958 11.5377 4.99308 10.5 6.82945 10.5H9.17055C11.0069 10.5 12.6804 11.5377 13.5 13.1709V14.5H2.5ZM6.82945 9C4.35483 9 2.10604 10.4388 1.06903 12.6857L1 12.8353V13V15.25V16H1.75H14.25H15V15.25V13V12.8353L14.931 12.6857C13.894 10.4388 11.6452 9 9.17055 9H6.82945Z'); path.setAttribute('fill', 'currentColor'); svg.appendChild(path); userBtn.appendChild(svg); loggedOutContainer.appendChild(userBtn); loggedOutContainer.style.display = 'flex'; loggedOutContainer.style.gap = '8px'; loggedOutContainer.style.alignItems = 'center'; user_status_content.firstChild.appendChild(loggedOutContainer); } })();
Menu

In this example, you will add a new redirect by staging a version with the redirect rule.

run.ts
import { Vercel } from '@vercel/sdk';
const vercel = new Vercel({
bearerToken: process.env.VERCEL_BEARER_TOKEN,
});
async function addRedirect() {
const teamId = process.env.VERCEL_TEAM_ID as string;
const projectId = process.env.VERCEL_PROJECT_ID as string;
try {
const result = await vercel.bulkRedirects.stageRedirects({
teamId,
requestBody: {
teamId,
projectId,
redirects: [
{
source: '/old-page',
destination: '/new-page',
statusCode: 308, // Permanent redirect
},
],
},
});
console.log(`Created redirect version: ${result.version?.id}`);
} catch (error) {
console.error(
error instanceof Error ? `Error: ${error.message}` : String(error),
);
}
}
addRedirect();

In this example, you promote a staged redirect version to active, making it live in production.

run.ts
import { Vercel } from '@vercel/sdk';
const vercel = new Vercel({
bearerToken: process.env.VERCEL_BEARER_TOKEN,
});
async function promoteRedirectVersion() {
const teamId = process.env.VERCEL_TEAM_ID as string;
const projectId = process.env.VERCEL_PROJECT_ID as string;
const versionId = 'your-version-id'; // The version ID to promote
try {
const result = await vercel.bulkRedirects.updateVersion({
teamId,
projectId,
requestBody: {
action: 'promote',
id: versionId,
},
});
console.log(`Promoted version to active`);
console.log('Version Details:', JSON.stringify(result.version, null, 2));
} catch (error) {
console.error(
error instanceof Error ? `Error: ${error.message}` : String(error),
);
}
}
promoteRedirectVersion();

In this example, you create a Next.js API route that receives redirect configurations from external systems (like a CMS) and uses the Vercel SDK to stage and promote bulk redirects automatically.

run.ts
import { NextResponse } from 'next/server';
import { Vercel } from '@vercel/sdk';
const vercel = new Vercel({
bearerToken: process.env.VERCEL_BEARER_TOKEN,
});
interface RedirectRule {
source: string;
destination: string;
statusCode?: 307 | 308 | 301 | 302;
}
interface WebhookPayload {
redirects: RedirectRule[];
autoPromote?: boolean;
}
export async function POST(request: Request) {
const teamId = process.env.VERCEL_TEAM_ID as string;
const projectId = process.env.VERCEL_PROJECT_ID as string;
if (!teamId || !projectId) {
return NextResponse.json(
{ error: 'Missing environment variables' },
{ status: 500 },
);
}
try {
const payload: WebhookPayload = await request.json();
if (!payload.redirects || !Array.isArray(payload.redirects)) {
return NextResponse.json(
{ error: 'Invalid payload: redirects array required' },
{ status: 400 },
);
}
// Stage new redirects
const stageResult = await vercel.bulkRedirects.stageRedirects({
teamId,
requestBody: {
teamId,
projectId,
redirects: payload.redirects.map((redirect) => ({
source: redirect.source,
destination: redirect.destination,
statusCode: redirect.statusCode || 308,
})),
},
});
const newVersion = stageResult.version;
if (!newVersion) {
return NextResponse.json(
{ error: 'Failed to create new version' },
{ status: 500 },
);
}
// Optionally auto-promote to production
if (payload.autoPromote) {
const publishResult = await vercel.bulkRedirects.updateVersion({
teamId,
projectId,
requestBody: {
action: 'promote',
id: newVersion.id,
},
});
if (!publishResult.version) {
return NextResponse.json(
{ error: 'Failed to publish new version' },
{ status: 500 },
);
}
return NextResponse.json({
message: 'Success!',
version: publishResult.version,
status: 'promoted',
});
}
return NextResponse.json({
message: 'Redirects staged successfully',
version: newVersion,
status: 'staged',
});
} catch (error) {
console.error('Error processing redirect webhook:', error);
return NextResponse.json(
{
error: 'Failed to process redirects',
details: error instanceof Error ? error.message : 'Unknown error',
},
{ status: 500 },
);
}
}