🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@passband.ai/sdk

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@passband.ai/sdk

Typed TypeScript client for the Passband /api/v1 REST API.

latest
Source
npmnpm
Version
0.1.0
Version published
Weekly downloads
0
-100%
Maintainers
1
Weekly downloads
 
Created
Source

@passband.ai/sdk

Typed TypeScript client for the Passband /api/v1 REST API.

The client is a thin, dependency-free wrapper over fetch. All request and response shapes are generated from the API's OpenAPI document, so the SDK cannot drift from the server.

Install

npm install @passband.ai/sdk
# or: pnpm add @passband.ai/sdk

Requires Node.js >= 18 (uses the global fetch). Ships ESM + CJS builds and types.

Usage

import { Passband } from '@passband.ai/sdk'

const pb = new Passband({ token: 'sf_...' })

// Run the content pipeline
await pb.pipeline.run()

// Review the ranked feed
const { drafts } = await pb.drafts.list({ status: 'pending_review' })

// Approve the first draft, if any
const first = drafts?.[0]
if (first) await pb.drafts.approve(first.id)

// Manage sources
await pb.sources.add({ name: 'HN', type: 'hackernews', url: 'https://news.ycombinator.com' })

Zero-config

With no options, the client reads PASSBAND_TOKEN (and PASSBAND_BASE_URL) from the environment:

// reads PASSBAND_TOKEN from process.env
const pb = new Passband()
const summary = await pb.engagement.summary()

Constructing without a token is allowed, but the first request throws PassbandAuthError — the SDK never sends an unauthenticated request.

Configuration

Constructor options take precedence over environment variables:

OptionEnv varDefault
tokenPASSBAND_TOKEN
baseUrlPASSBAND_BASE_URLhttps://passband.ai
fetchglobal fetch
retrydisabled

The token is sent as Authorization: Bearer <token>.

Pagination

List endpoints are cursor-paginated. list() returns a single page (with a nextCursor). For drafts, drafts.iterate() returns an async iterator that transparently follows nextCursor:

for await (const draft of pb.drafts.iterate({ status: 'pending_review' })) {
  console.log(draft.id)
}

Retries

Retries are opt-in. When enabled, the client retries 429 (honoring Retry-After) and 5xx responses with exponential backoff and full jitter. Other 4xx responses are never retried.

By default only idempotent methods are retried (GET/PUT/DELETE/PATCH). POST is not retried, to avoid duplicating side effects. If your POST endpoints are idempotent, opt in with retryNonIdempotent: true.

const pb = new Passband({
  token: 'sf_...',
  retry: { retries: 3, backoff: 250, retryNonIdempotent: false },
})

Cancellation via AbortSignal is never retried: the original AbortError (or your signal.reason) is re-thrown unchanged.

Errors

Every non-2xx response throws a typed error: PassbandAuthError (401), PassbandForbiddenError (403), PassbandNotFoundError (404), PassbandRateLimitError (429, with retryAfter), and PassbandServerError (5xx). Network and parse failures throw PassbandNetworkError. All extend PassbandError with status, code, message, body, and requestId.

import {
  Passband,
  PassbandRateLimitError,
  PassbandNotFoundError,
  PassbandError,
} from '@passband.ai/sdk'

const pb = new Passband({ token: 'sf_...' })

try {
  await pb.drafts.approve('draft_123')
} catch (err) {
  if (err instanceof PassbandRateLimitError) {
    console.warn(`Rate limited; retry after ${err.retryAfter}s`)
  } else if (err instanceof PassbandNotFoundError) {
    console.warn('Draft not found')
  } else if (err instanceof PassbandError) {
    console.error(err.status, err.code, err.message, err.requestId, err.body)
  } else {
    throw err
  }
}

Resources

NamespaceMethods
pb.pipelinerun, status(runId), stats, runs.list
pb.draftslist, iterate, get, create, update, approve, post, bulk
pb.sourceslist, add, update, remove, test
pb.voiceget, update
pb.engagementsummary, upsert
pb.experimentslist, create

pipeline.status(runId) has no dedicated API route — it performs an O(n) linear scan of pipeline.runs.list (capped at the most recent ~2000 runs) and throws PassbandNotFoundError when the run isn't found. Prefer paging pipeline.runs.list directly when you already know the run is recent.

Examples

Runnable end-to-end examples live in examples/ — including agent-flow.ts, the canonical loop (run pipeline → ranked feed → approve drafts → add sources). Each reads PASSBAND_TOKEN from the environment; see examples/README.md.

Docs

Generate the static API + REST reference (typedoc + Redocly) into docs/:

pnpm --filter @passband.ai/sdk run docs   # use `run docs` — bare `pnpm docs` is intercepted by pnpm

Development

pnpm --filter @passband.ai/sdk generate   # regenerate openapi.json + types
pnpm --filter @passband.ai/sdk build      # tsup → ESM + CJS + d.ts
pnpm --filter @passband.ai/sdk test       # vitest (unit + OpenAPI contract)

Types are generated from app/api/v1/docs/openapi.ts (the single source of truth, also served at /api/v1/docs). Run generate after changing the API.

Keywords

passband

FAQs

Package last updated on 10 Jun 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts