VE

vercel-sdk-patterns

Provides typed, robust REST API wrappers for interacting with the Vercel platform programmatically.

Install

mkdir -p .claude/skills/vercel-sdk-patterns && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/5971" && unzip -o skill.zip -d .claude/skills/vercel-sdk-patterns && rm skill.zip

Installs to .claude/skills/vercel-sdk-patterns

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Production-ready Vercel REST API patterns with typed fetch wrappers
67 charsno explicit “when” trigger
Intermediate

Key capabilities

  • Create a typed Vercel API client
  • Implement custom error handling for Vercel API responses
  • Apply retry logic with exponential backoff for API calls
  • Handle paginated data fetching from Vercel API
  • Manage Vercel projects, deployments, environment variables, and domains

How it works

The skill builds a TypeScript client with a request method that handles authentication, error responses, and retries, and defines types for Vercel resources.

Inputs & outputs

You give it
Vercel API access token and specific API operations (e.g., list projects, create environment variable)
You get back
Type-safe Vercel API client with error handling, retry logic, and paginated data fetching

When to use vercel-sdk-patterns

  • Build internal deployment automation tools
  • Create typed clients for Vercel API endpoints
  • Handle API rate limiting and errors
  • Automate environment variable updates

About this skill

Vercel SDK Patterns

Overview

Build a typed, production-ready wrapper around the Vercel REST API (api.vercel.com). Covers authentication, pagination, error handling, retry logic, and common endpoint patterns for deployments, projects, and environment variables.

Prerequisites

  • Completed vercel-install-auth setup
  • TypeScript project with strict mode enabled
  • Vercel access token with appropriate scope

Instructions

Step 1: Create Typed API Client

// lib/vercel-client.ts
interface VercelClientConfig {
  token: string;
  teamId?: string;
  baseUrl?: string;
}

interface VercelError {
  error: { code: string; message: string };
}

class VercelClient {
  private token: string;
  private teamId?: string;
  private baseUrl: string;

  constructor(config: VercelClientConfig) {
    this.token = config.token;
    this.teamId = config.teamId;
    this.baseUrl = config.baseUrl ?? 'https://api.vercel.com';
  }

  private async request<T>(
    method: string,
    path: string,
    body?: unknown
  ): Promise<T> {
    const url = new URL(path, this.baseUrl);
    if (this.teamId) url.searchParams.set('teamId', this.teamId);

    const res = await fetch(url.toString(), {
      method,
      headers: {
        Authorization: `Bearer ${this.token}`,
        'Content-Type': 'application/json',
      },
      body: body ? JSON.stringify(body) : undefined,
    });

    if (!res.ok) {
      const err: VercelError = await res.json();
      throw new VercelApiError(res.status, err.error.code, err.error.message);
    }

    // 204 No Content
    if (res.status === 204) return undefined as T;
    return res.json() as Promise<T>;
  }

  // --- Projects ---
  async listProjects(limit = 20) {
    return this.request<{ projects: VercelProject[] }>(
      'GET', `/v9/projects?limit=${limit}`
    );
  }

  async getProject(idOrName: string) {
    return this.request<VercelProject>('GET', `/v9/projects/${idOrName}`);
  }

  // --- Deployments ---
  async listDeployments(projectId?: string, limit = 20) {
    const params = new URLSearchParams({ limit: String(limit) });
    if (projectId) params.set('projectId', projectId);
    return this.request<{ deployments: VercelDeployment[] }>(
      'GET', `/v6/deployments?${params}`
    );
  }

  async getDeployment(idOrUrl: string) {
    return this.request<VercelDeployment>(
      'GET', `/v13/deployments/${idOrUrl}`
    );
  }

  // --- Environment Variables ---
  async listEnvVars(projectId: string) {
    return this.request<{ envs: VercelEnvVar[] }>(
      'GET', `/v9/projects/${projectId}/env`
    );
  }

  async createEnvVar(projectId: string, envVar: CreateEnvVarInput) {
    return this.request<VercelEnvVar>(
      'POST', `/v9/projects/${projectId}/env`, envVar
    );
  }

  // --- Domains ---
  async listDomains(projectId: string) {
    return this.request<{ domains: VercelDomain[] }>(
      'GET', `/v9/projects/${projectId}/domains`
    );
  }

  async addDomain(projectId: string, domain: string) {
    return this.request<VercelDomain>(
      'POST', `/v9/projects/${projectId}/domains`, { name: domain }
    );
  }
}

Step 2: Define Types

// lib/vercel-types.ts
interface VercelProject {
  id: string;
  name: string;
  framework: string | null;
  latestDeployments: VercelDeployment[];
  targets: Record<string, VercelDeployment>;
  createdAt: number;
  updatedAt: number;
}

interface VercelDeployment {
  uid: string;
  name: string;
  url: string;
  state: 'BUILDING' | 'ERROR' | 'INITIALIZING' | 'QUEUED' | 'READY' | 'CANCELED';
  target: 'production' | 'preview' | null;
  createdAt: number;
  buildingAt: number;
  ready: number;
  meta: Record<string, string>;
}

interface VercelEnvVar {
  id: string;
  key: string;
  value: string;
  type: 'system' | 'encrypted' | 'plain' | 'sensitive';
  target: ('production' | 'preview' | 'development')[];
  createdAt: number;
  updatedAt: number;
}

interface CreateEnvVarInput {
  key: string;
  value: string;
  type: 'encrypted' | 'plain' | 'sensitive';
  target: ('production' | 'preview' | 'development')[];
}

interface VercelDomain {
  name: string;
  verified: boolean;
  redirect: string | null;
  gitBranch: string | null;
  createdAt: number;
  updatedAt: number;
}

Step 3: Custom Error Class

// lib/vercel-errors.ts
class VercelApiError extends Error {
  constructor(
    public status: number,
    public code: string,
    message: string
  ) {
    super(`Vercel API ${status}: [${code}] ${message}`);
    this.name = 'VercelApiError';
  }

  get isRateLimit(): boolean { return this.status === 429; }
  get isNotFound(): boolean { return this.status === 404; }
  get isUnauthorized(): boolean { return this.status === 401 || this.status === 403; }
}

Step 4: Retry with Exponential Backoff

// lib/vercel-retry.ts
async function withRetry<T>(
  fn: () => Promise<T>,
  maxRetries = 3,
  baseDelayMs = 1000
): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (err instanceof VercelApiError && err.isRateLimit && attempt < maxRetries) {
        const delay = baseDelayMs * Math.pow(2, attempt) + Math.random() * 500;
        console.warn(`Rate limited. Retrying in ${Math.round(delay)}ms...`);
        await new Promise(r => setTimeout(r, delay));
        continue;
      }
      throw err;
    }
  }
  throw new Error('Unreachable');
}

// Usage:
// const projects = await withRetry(() => client.listProjects());

Step 5: Paginated Fetching

// lib/vercel-pagination.ts
async function* paginateDeployments(
  client: VercelClient,
  projectId: string,
  pageSize = 100
): AsyncGenerator<VercelDeployment[]> {
  let until: number | undefined;

  while (true) {
    const params = new URLSearchParams({ limit: String(pageSize) });
    if (until) params.set('until', String(until));
    if (projectId) params.set('projectId', projectId);

    const { deployments } = await client.listDeployments(projectId, pageSize);
    if (deployments.length === 0) break;

    yield deployments;
    until = deployments[deployments.length - 1].createdAt;
    if (deployments.length < pageSize) break;
  }
}

API Endpoint Quick Reference

OperationMethodEndpoint
List projectsGET/v9/projects
Get projectGET/v9/projects/{idOrName}
Delete projectDELETE/v9/projects/{idOrName}
List deploymentsGET/v6/deployments
Create deploymentPOST/v13/deployments
Get deploymentGET/v13/deployments/{id}
Delete deploymentDELETE/v13/deployments/{id}
List env varsGET/v9/projects/{id}/env
Create env varPOST/v9/projects/{id}/env
Edit env varPATCH/v9/projects/{id}/env/{envId}
Delete env varDELETE/v9/projects/{id}/env/{envId}
Add domainPOST/v9/projects/{id}/domains
Verify domainPOST/v9/projects/{id}/domains/{domain}/verify
List teamsGET/v2/teams

Output

  • Type-safe Vercel API client with full TypeScript coverage
  • Custom error class with semantic helpers (isRateLimit, isNotFound)
  • Automatic retry with exponential backoff for 429 responses
  • Paginated data fetching for large result sets

Error Handling

ErrorStatusSolution
forbidden403Token lacks scope — regenerate with correct permissions
not_found404Check project/deployment ID is correct
rate_limited429Use withRetry() wrapper — waits and retries automatically
team_not_found404Verify teamId parameter matches your team
bad_request400Validate request body matches API schema

Resources

Next Steps

Proceed to vercel-deploy-preview for preview deployment workflows.

Prerequisites

Completed `vercel-install-auth` setupTypeScript project with `strict` mode enabledVercel access token with appropriate scope

Limitations

  • Token lacking scope for forbidden (403) errors
  • Incorrect project/deployment ID for not_found (404) errors
  • Request body not matching API schema for bad_request (400) errors

How it compares

This skill provides a structured, type-safe, and resilient wrapper for the Vercel REST API, contrasting with direct API calls that require manual handling of authentication, errors, and pagination.

Compared to similar skills

vercel-sdk-patterns side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
vercel-sdk-patterns (this skill)127dReviewIntermediate
mcporter72moNo flagsIntermediate
calcom-api24moNo flagsIntermediate
developing-genkit-tooling26moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

More by jeremylongshore

View all by jeremylongshore

analyzing-logs

jeremylongshore

Analyze application logs to detect performance issues, identify error patterns, and improve stability by extracting key insights.

14123

ollama-setup

jeremylongshore

Configure auto-configure Ollama when user needs local LLM deployment, free AI alternatives, or wants to eliminate hosted API costs. Trigger phrases: "install ollama", "local AI", "free LLM", "self-hosted AI", "replace OpenAI", "no API costs". Use when appropriate context detected. Trigger with relevant phrases based on skill purpose.

1167

backtesting-trading-strategies

jeremylongshore

Backtest crypto and traditional trading strategies against historical data. Calculates performance metrics (Sharpe, Sortino, max drawdown), generates equity curves, and optimizes strategy parameters. Use when user wants to test a trading strategy, validate signals, or compare approaches. Trigger with phrases like "backtest strategy", "test trading strategy", "historical performance", "simulate trades", "optimize parameters", or "validate signals".

1071

generating-database-seed-data

jeremylongshore

Process this skill enables AI assistant to generate realistic test data and database seed scripts for development and testing environments. it uses faker libraries to create realistic data, maintains relational integrity, and allows configurable data volumes. u... Use when working with databases or data models. Trigger with phrases like 'database', 'query', or 'schema'.

1033

cursor-codebase-indexing

jeremylongshore

Execute set up and optimize Cursor codebase indexing. Triggers on "cursor index setup", "codebase indexing", "index codebase", "cursor semantic search". Use when working with cursor codebase indexing functionality. Trigger with phrases like "cursor codebase indexing", "cursor indexing", "cursor".

885

testing-mobile-apps

jeremylongshore

Execute mobile app testing on iOS and Android devices/simulators. Use when performing specialized testing. Trigger with phrases like "test mobile app", "run iOS tests", or "validate Android functionality".

810

You might also like

mcporter

openclaw

Use the mcporter CLI to list, configure, auth, and call MCP servers/tools directly (HTTP or stdio), including ad-hoc servers, config edits, and CLI/type generation.

726

calcom-api

calcom

Interact with the Cal.com API v2 to manage scheduling, bookings, event types, availability, and calendars. Use this skill when building integrations that need to create or manage bookings, check availability, configure event types, or sync calendars with Cal.com's scheduling infrastructure.

216

developing-genkit-tooling

firebase

Best practices for authoring Genkit tooling, including CLI commands and MCP server tools. Covers naming conventions, architectural patterns, and consistency guidelines.

27

deepgram-webhooks-events

jeremylongshore

Implement Deepgram callback and webhook handling for async transcription. Use when implementing callback URLs, processing async transcription results, or handling Deepgram event notifications. Trigger with phrases like "deepgram callback", "deepgram webhook", "async transcription deepgram", "deepgram events", "deepgram notifications".

01

replit-webhooks-events

jeremylongshore

Implement Replit webhook signature validation and event handling. Use when setting up webhook endpoints, implementing signature verification, or handling Replit event notifications securely. Trigger with phrases like "replit webhook", "replit events", "replit webhook signature", "handle replit events", "replit notifications".

01

instantly-core-workflow-b

jeremylongshore

Execute Instantly secondary workflow: Core Workflow B. Use when implementing secondary use case, or complementing primary workflow. Trigger with phrases like "instantly secondary workflow", "secondary task with instantly".

00

Search skills

Search the agent skills registry