SDK API

SDK API

The Leash SDK exposes everything the platform offers as one client: new Leash({ request }). This page is the surface reference — namespaces, methods, signatures.

For the tiered journey (when to use what, how production differs), see Building with Leash. For the canonical local-dev setup, see Local dev.

Install

Terminal

$ npm install @leash/sdk

TypeScript SDK. Python, Go, Ruby, Rust, Java in progress — see the per-language docs once they ship.

Construct

Always server-side. Pass the incoming request so the SDK can read the leash-auth cookie and route per-user calls correctly. The API key is auto-read from LEASH_API_KEY.

app/api/example/route.ts
import { Leash } from '@leash/sdk/leash'
export async function GET(req: Request) {
const leash = new Leash({ request: req })
// ...use leash.integrations, leash.env, leash.auth
return Response.json({ ok: true })
}

leash.integrations

Call third-party APIs on behalf of the calling user. Leash brokers OAuth and refresh. See Integrations for the full per-provider catalog.

.gmail

Typed Gmail calls as the connected user.

// leash.integrations.gmail
listMessages(params?: { query?: string; maxResults?: number; labelIds?: string[]; pageToken?: string }): Promise<GmailMessageList>
getMessage(messageId: string, format?: 'full' | 'metadata' | 'minimal' | 'raw'): Promise<unknown>
sendMessage(message: { to: string; subject: string; body: string; cc?: string; bcc?: string }): Promise<unknown>
searchMessages(query: string, maxResults?: number): Promise<GmailMessageList>
listLabels(): Promise<GmailLabelList>
getProfile(): Promise<unknown>

.calendar

Typed Google Calendar calls.

// leash.integrations.calendar
listCalendars(): Promise<CalendarList>
listEvents(params?: {
calendarId?: string
timeMin?: string
timeMax?: string
maxResults?: number
query?: string
singleEvents?: boolean
orderBy?: string
}): Promise<CalendarEventList>
createEvent(params: {
calendarId?: string
summary: string
description?: string
location?: string
start: { dateTime?: string; date?: string; timeZone?: string }
end: { dateTime?: string; date?: string; timeZone?: string }
attendees?: { email: string }[]
}): Promise<CalendarEvent>
getEvent(eventId: string, calendarId?: string): Promise<CalendarEvent>

.drive

Typed Google Drive calls.

// leash.integrations.drive
listFiles(params?: { query?: string; maxResults?: number; folderId?: string }): Promise<DriveFileList>
getFile(fileId: string): Promise<DriveFile>
downloadFile(fileId: string): Promise<unknown>
createFolder(name: string, parentId?: string): Promise<DriveFile>
uploadFile(params: { name: string; content: string; mimeType: string; parentId?: string }): Promise<DriveFile>
deleteFile(fileId: string): Promise<unknown>
searchFiles(query: string, maxResults?: number): Promise<DriveFileList>

.linear

Typed Linear calls — issues, comments, teams, projects.

// leash.integrations.linear
listIssues(filter?: {
teamId?: string
assigneeId?: string
stateType?: 'backlog' | 'unstarted' | 'started' | 'completed' | 'canceled' | 'triage'
limit?: number
cursor?: string
}): Promise<{ issues: LinearIssue[]; cursor?: string }>
getIssue(id: string): Promise<LinearIssue>
createIssue(input: {
teamId: string
title: string
description?: string
assigneeId?: string
priority?: 0 | 1 | 2 | 3 | 4
labelIds?: string[]
}): Promise<LinearIssue>
updateIssue(id: string, patch: Partial<LinearCreateIssueInput>): Promise<LinearIssue>
addComment(issueId: string, body: string): Promise<LinearComment>
listTeams(): Promise<LinearTeam[]>
listProjects(filter?: { teamId?: string }): Promise<LinearProject[]>

Example usage:

const messages = await leash.integrations.gmail.listMessages({
query: 'newer_than:1d',
maxResults: 10,
})
const issues = await leash.integrations.linear.listIssues({ teamId: 'eng', limit: 20 })

leash.env

Fetch dynamic env vars at runtime — rotation without redeploy, audit trail, central revocation. For static values use process.env (see App env vars).

// leash.env
get(key: string, opts?: { fresh?: boolean }): Promise<string>
getMany(keys: string[]): Promise<Record<string, string>>

Example usage:

const stripeKey = await leash.env.get('STRIPE_SECRET_KEY')
const { OPENAI_API_KEY, STRIPE_KEY } = await leash.env.getMany([
'OPENAI_API_KEY',
'STRIPE_KEY',
])

See Dynamic env vars for setup and source configuration.

leash.auth

Identify the user making the request. Sync, null-returning — no try/catch needed.

// leash.auth
user(): LeashUser | null
isAuthenticated(): boolean
attachLocalDevHandler(opts?: { cookieName?: string; cookieMaxAge?: number; redirectTo?: string }): (req: unknown) => Promise<Response>

Example usage:

app/api/me/route.ts
export async function GET(req: Request) {
const leash = new Leash({ request: req })
const user = leash.auth.user()
if (!user) return Response.json({ error: 'unauthorized' }, { status: 401 })
return Response.json({ id: user.id, email: user.email, name: user.name })
}

See Local dev for the dev-auth handler setup.

Leash.createDevAuthHandler()

Static factory. Returns a route handler that exchanges a Leash dashboard code for a local leash-auth cookie on localhost. Wire once per project.

// Leash.createDevAuthHandler
static createDevAuthHandler(opts?: { cookieName?: string; cookieMaxAge?: number; redirectTo?: string }): (req: unknown) => Promise<Response>

Example usage:

app/api/leash/dev-auth/route.ts
import { Leash } from '@leash/sdk/leash'
export const GET = Leash.createDevAuthHandler()

The folder MUST be named leash — Next.js excludes _-prefixed folders from routing. See Local dev for the full flow.

LeashError

Every SDK error is a LeashError with a machine-readable code and a human-readable action. See Error handling for the full code list.

import { Leash, LeashError } from '@leash/sdk/leash'
try {
await leash.integrations.gmail.listMessages(...)
} catch (err) {
if (err instanceof LeashError) {
console.error(err.code, err.toString())
}
}