@brew.new/sdk
v10.0.0
Published
Official TypeScript SDK for the Brew public API.
Readme
@brew.new/sdk
Official TypeScript SDK for the Brew public API.
- Resource-oriented surface —
brew.contacts.upsert(...)instead of raw HTTP plumbing. - One typed error class (
BrewApiError) for every non-2xx path. - Safe retries with exponential backoff + jitter.
- Auto-generated
Idempotency-Keyon POST so retries never double-write. - Node 20+, server-first. API keys are secrets — do not use this SDK directly in a browser.
Install
bun add @brew.new/sdk
# or
npm install @brew.new/sdkQuick start
import { createBrewClient } from '@brew.new/sdk'
const brew = createBrewClient({
apiKey: process.env.BREW_API_KEY!,
})
const contact = await brew.contacts.upsert({
email: '[email protected]',
firstName: 'Jane',
customFields: { plan: 'enterprise' },
})
const found = await brew.contacts.get('[email protected]')
const { data } = await brew.contacts.search({
filters: [
{ field: 'customFields.plan', operator: 'equals', value: 'enterprise' },
],
})That's the whole shape. Every other method follows the same pattern:
list(query) for a page, get(id) for the bare row, and a 404 — not
an empty page — when the id is unknown.
Upgrading from 9.x? 10.0.0 is a breaking release that tracks the public API v1 cleanup. Read the CHANGELOG for the full migration table.
Pointing at a different environment
baseUrl is configurable. By default it points at production
(https://brew.new/api), but you can override it for staging, local
development, or a custom proxy:
const brew = createBrewClient({
apiKey: process.env.BREW_API_KEY!,
baseUrl: process.env.BREW_API_URL ?? 'https://brew.new/api',
})Common values:
https://brew.new/api— production (default)https://staging.brew.new/api— staginghttp://localhost:3000/api— your own dev server
Trailing slashes are normalized either way. See
docs/configuration.md for the full list of
config options (timeoutMs, maxRetries, userAgent, custom fetch,
etc.).
Documentation
| Topic | File |
| ---------------------------------- | ---------------------------------------------------------------------- |
| Analytics resource | docs/analytics.md |
| Automations resource | docs/automations.md |
| Audiences resource | docs/audiences.md |
| Brand resource | docs/brand.md |
| Brands (lifecycle) | docs/brands.md |
| Client configuration | docs/configuration.md |
| Contacts resource | docs/contacts.md |
| Domains resource | docs/domains.md |
| Emails resource (+ send) | docs/emails.md |
| Fields resource | docs/fields.md |
| Error handling | docs/errors.md |
| Retries + idempotency | docs/retries-and-idempotency.md |
| Sends resource (reads + lifecycle) | docs/sends.md |
| Templates resource | docs/templates.md |
| Flows resource | docs/flows.md |
| Development + OpenAPI sync | docs/development.md |
| Releasing a new version | RELEASING.md |
Note:
brew.brand.*(singular) reads the brand the CURRENT request acts on — its design system, identity, and extraction readiness.brew.brands.*(plural) is the organization-level lifecycle: list, create, and poll brands.An API key is scoped either to ONE BRAND or to the whole ORGANIZATION. A brand-scoped key resolves its brand automatically. An organization-scoped key must name one per request — pass
brandIdin the client config, or pin one withclient.withBrand(id). There is no default brand: omitting it returns400 BRAND_ID_REQUIRED.const brew = createBrewClient({ apiKey: process.env.BREW_API_KEY! }) const { data: brands } = await brew.brands.list() const acme = brew.withBrand(brands[0].brandId) await acme.emails.list()
Development
Use a modern Node 20 or newer runtime for SDK development. On this
machine, Vitest worked with Node 20.19.2 and newer, but failed on the
older system Node 20.10.0.
bun install
bun tsc # typecheck
bun lint # eslint
bun run format # prettier
bun run test # vitest — NOT `bun test`, that hits Bun's built-in runner and bypasses MSW setup
bun run build # tsup: dist/ with esm + cjs + .d.tsFull contribution + testing conventions live in AGENTS.md.
The big one: every change is driven red → green via vitest + MSW, no
exceptions for "trivial" pure functions.
License
MIT
