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
$ 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.
import { Leash } from '@leash/sdk/leash'export async function GET(req: Request) {const leash = new Leash({ request: req })// ...use leash.integrations, leash.env, leash.authreturn 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.gmaillistMessages(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.calendarlistCalendars(): Promise<CalendarList>listEvents(params?: {calendarId?: stringtimeMin?: stringtimeMax?: stringmaxResults?: numberquery?: stringsingleEvents?: booleanorderBy?: string}): Promise<CalendarEventList>createEvent(params: {calendarId?: stringsummary: stringdescription?: stringlocation?: stringstart: { 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.drivelistFiles(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.linearlistIssues(filter?: {teamId?: stringassigneeId?: stringstateType?: 'backlog' | 'unstarted' | 'started' | 'completed' | 'canceled' | 'triage'limit?: numbercursor?: string}): Promise<{ issues: LinearIssue[]; cursor?: string }>getIssue(id: string): Promise<LinearIssue>createIssue(input: {teamId: stringtitle: stringdescription?: stringassigneeId?: stringpriority?: 0 | 1 | 2 | 3 | 4labelIds?: 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.envget(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.authuser(): LeashUser | nullisAuthenticated(): booleanattachLocalDevHandler(opts?: { cookieName?: string; cookieMaxAge?: number; redirectTo?: string }): (req: unknown) => Promise<Response>
Example usage:
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.createDevAuthHandlerstatic createDevAuthHandler(opts?: { cookieName?: string; cookieMaxAge?: number; redirectTo?: string }): (req: unknown) => Promise<Response>
Example usage:
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())}}