Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.brew.new/llms.txt

Use this file to discover all available pages before exploring further.

Create The Client

Get an API key from brew.new/settings/api. Each key is bound to one brand at creation — pick the brand you want this client to act on before generating.
import { createBrewClient } from '@brew.new/sdk'

const brew = createBrewClient({
  apiKey: process.env.BREW_API_KEY!,
})

1. Upsert A Contact

const contactResult = await brew.contacts.upsert({
  email: 'john@example.com',
  firstName: 'John',
  lastName: 'Doe',
  subscribed: true,
  customFields: {
    plan: 'enterprise',
  },
})

console.log(contactResult.contact.email)
console.log(contactResult.created)

2. Browse Public Templates (optional)

const { templates } = await brew.templates.list({
  brand: 'vercel.com',
})
Templates are public reference emails. Pass any one as referenceEmailId to email generation when you want to anchor the output on its layout. Your own brand design context is automatic — every API key is bound to one brand at creation, and brew.emails.generate grounds itself in that brand without you ever passing a brandId.

3. Generate An Email

const generated = await brew.emails.generate({
  prompt: 'Create a welcome email for new subscribers',
  referenceEmailId: templates[0]?.emailId,
})

if ('emailId' in generated) {
  console.log(generated.emailId)
  console.log(generated.emailHtml)
} else {
  console.log(generated.response)
}

4. Edit A Saved Email (optional)

brew.emails.edit runs the agent against an existing email’s current latest JSX and persists a new version: "latest" row on the same emailId, demoting the previous head to a numeric historical version.
if ('emailId' in generated) {
  const edited = await brew.emails.edit({
    emailId: generated.emailId,
    prompt: 'Tighten the headline and add a friendlier sign-off.',
  })

  if ('emailId' in edited) {
    console.log(edited.emailId, edited.emailHtml)
  }
}
The brand is resolved from the API key. The emailId is a path parameter — neither brandId nor emailId may appear in the body.

5. List Verified Domains

const { domains } = await brew.domains.list()

if (domains.length === 0) {
  throw new Error('You need a verified sending domain before sending.')
}

6. Start A Send

Use one recipient mode.
  • audienceId
  • emails
Manual email mode example:
if ('emailId' in generated) {
  const sendResult = await brew.sends.create({
    emailId: generated.emailId,
    domainId: domains[0]!.domainId,
    subject: 'Welcome to Brew',
    emails: ['john@example.com'],
  })

  console.log(sendResult.status)
  console.log(sendResult.runId)
}
Scheduled send example:
await brew.sends.create({
  emailId: 'email_123',
  domainId: 'domain_123',
  subject: 'Launch update',
  emails: ['john@example.com'],
  scheduledAt: '2099-01-01T00:00:00.000Z',
})

Handle Errors

import { BrewApiError } from '@brew.new/sdk'

try {
  await brew.domains.list()
} catch (error) {
  if (error instanceof BrewApiError) {
    console.error(error.code, error.message, error.requestId)
  }
  throw error
}

Next Steps

Resource Surface

See the current TypeScript SDK resources and methods.

API Reference

See the raw HTTP contract behind the SDK.

Need Help?

Our team is ready to support you at every step of your journey with Brew. Choose the option that works best for you:

Search Documentation

Type in the “Ask any question” search bar at the top left to instantly find relevant documentation pages.

ChatGPT/Claude Integration

Click “Open in ChatGPT” at the top right of any page to analyze documentation with ChatGPT or Claude for deeper insights.