Back to list
ADLenehan

vercel-api

by ADLenehan

Safe hosting for the non-technical

0🍴 0📅 Jan 13, 2026

SKILL.md


name: vercel-api description: Patterns for programmatic deployment via Vercel API. Use this skill when implementing deployment workflows, managing projects, configuring environment variables, or setting up domains.

Vercel API Patterns

API Client Setup

const VERCEL_API = 'https://api.vercel.com'

interface VercelClientConfig {
  token: string
  teamId?: string
}

class VercelClient {
  constructor(private config: VercelClientConfig) {}

  private async request<T>(
    path: string,
    options: RequestInit = {}
  ): Promise<T> {
    const url = new URL(path, VERCEL_API)

    if (this.config.teamId) {
      url.searchParams.set('teamId', this.config.teamId)
    }

    const response = await fetch(url, {
      ...options,
      headers: {
        Authorization: `Bearer ${this.config.token}`,
        'Content-Type': 'application/json',
        ...options.headers,
      },
    })

    if (!response.ok) {
      const error = await response.json()
      throw new VercelAPIError(error.error.message, response.status)
    }

    return response.json()
  }
}

Project Creation

interface CreateProjectRequest {
  name: string
  framework?: 'nextjs' | 'vite' | 'remix' | null
  gitRepository?: {
    type: 'github' | 'gitlab' | 'bitbucket'
    repo: string
  }
  buildCommand?: string
  outputDirectory?: string
  rootDirectory?: string
}

async createProject(data: CreateProjectRequest) {
  return this.request<Project>('/v10/projects', {
    method: 'POST',
    body: JSON.stringify(data),
  })
}

Environment Variables

Set Environment Variables

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

async setEnvVariables(projectId: string, variables: EnvVariable[]) {
  return this.request(`/v10/projects/${projectId}/env`, {
    method: 'POST',
    body: JSON.stringify(variables),
  })
}

Get Environment Variables

async getEnvVariables(projectId: string) {
  return this.request<{ envs: EnvVariable[] }>(
    `/v9/projects/${projectId}/env`
  )
}

Deployment

Create Deployment from Files

interface DeploymentFile {
  file: string
  data: string // base64 encoded
}

async createDeployment(projectId: string, files: DeploymentFile[]) {
  return this.request<Deployment>('/v13/deployments', {
    method: 'POST',
    body: JSON.stringify({
      name: projectId,
      files,
      projectSettings: {
        framework: 'nextjs',
      },
    }),
  })
}

Check Deployment Status

type DeploymentState =
  | 'QUEUED'
  | 'BUILDING'
  | 'READY'
  | 'ERROR'
  | 'CANCELED'

async getDeployment(deploymentId: string) {
  return this.request<Deployment>(`/v13/deployments/${deploymentId}`)
}

async waitForDeployment(
  deploymentId: string,
  timeout = 300000
): Promise<Deployment> {
  const start = Date.now()

  while (Date.now() - start < timeout) {
    const deployment = await this.getDeployment(deploymentId)

    if (deployment.readyState === 'READY') {
      return deployment
    }

    if (deployment.readyState === 'ERROR') {
      throw new Error(`Deployment failed: ${deployment.errorMessage}`)
    }

    await new Promise((r) => setTimeout(r, 2000))
  }

  throw new Error('Deployment timeout')
}

Domain Configuration

Add Domain

async addDomain(projectId: string, domain: string) {
  return this.request(`/v10/projects/${projectId}/domains`, {
    method: 'POST',
    body: JSON.stringify({ name: domain }),
  })
}

Configure Subdomain

Battery uses subdomains for deployed apps: {app-name}.{org}.battery.app

async configureBatteryDomain(
  projectId: string,
  appName: string,
  orgSlug: string
) {
  const domain = `${appName}.${orgSlug}.battery.app`
  return this.addDomain(projectId, domain)
}

Error Handling

class VercelAPIError extends Error {
  constructor(
    message: string,
    public statusCode: number
  ) {
    super(message)
    this.name = 'VercelAPIError'
  }
}

// Handle common errors
try {
  await client.createProject({ name: 'my-app' })
} catch (error) {
  if (error instanceof VercelAPIError) {
    switch (error.statusCode) {
      case 400:
        // Invalid request
        break
      case 401:
        // Invalid token
        break
      case 403:
        // Insufficient permissions
        break
      case 409:
        // Project already exists
        break
    }
  }
}

Rate Limiting

Vercel API has rate limits. Implement backoff:

async function withRetry<T>(
  fn: () => Promise<T>,
  maxRetries = 3
): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn()
    } catch (error) {
      if (
        error instanceof VercelAPIError &&
        error.statusCode === 429 &&
        i < maxRetries - 1
      ) {
        await new Promise((r) => setTimeout(r, 2 ** i * 1000))
        continue
      }
      throw error
    }
  }
  throw new Error('Max retries exceeded')
}

Key Endpoints Reference

OperationMethodEndpoint
List projectsGET/v9/projects
Create projectPOST/v10/projects
Get projectGET/v9/projects/{idOrName}
Delete projectDELETE/v9/projects/{idOrName}
Create deploymentPOST/v13/deployments
Get deploymentGET/v13/deployments/{id}
List deploymentsGET/v6/deployments
Set env varsPOST/v10/projects/{id}/env
Add domainPOST/v10/projects/{id}/domains

Score

Total Score

50/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon