# Start a newsletter

URL: /systems/marketing/start-a-newsletter · Id: `guide:start-a-newsletter` · Status: `planned`

> Say "start a newsletter" and get a signup box on your page, a Consent record per subscriber, and each issue sent to every one of them.

Collect subscribers on your page and send them each issue by email. Its status is `planned`: your agent tells you so and runs nothing yet.

Needs: [Get email at my domain](/products/site/domains/get-email-at-my-domain)

**Before it runs**

- Who says yes: You, for its `send`. Your agent shows you the run and waits for your [Approval](/business/nouns/approval).
- You leave the chat: Never.
- What it costs: Nothing. A paid tier pays the card fee on each charge.
- To undo it: Delete the Newsletter; it stays restorable, and every subscriber keeps their Consent record.

## What you get
- 1 Newsletter with a signup box on your page (Newsletter)
- 1 Consent record per subscriber (Consent)
- 1 issue sent, with an unsubscribe link in every email (Message)

## Your agent does
**For agents**

- Guide: `guide:start-a-newsletter`, status `planned`: say it is planned; do not run it. Page: [/systems/marketing/start-a-newsletter.md](/systems/marketing/start-a-newsletter.md).
- Approval: ask the founder first. Show the run, then wait for their Approval; a refusal ends it. Action class: `send`.
- Leaves the chat: never.
- Needs first: [Get email at my domain](/products/site/domains/get-email-at-my-domain).
- Run: call the steps in order, each through the API, SDK, CLI or MCP tab below; a later step passes the `$id` an earlier one returns. Each value marked example is the sample business’s: pass the founder’s own.

| Step | Verb | Inputs (type, required, this guide’s value) | Returns |
| --- | --- | --- | --- |
| 1 | [`Newsletter.create`](/business/nouns/newsletter/create) (`verb:Newsletter.create`) | `name` string, required: example `"Renewal notes"`; `from` Mailbox (an id), required: the `$id` of the first Mailbox `Mailbox.list` returns; `topic` string: example `"renewal-notes"` | `newsletter` Newsletter |
| 2 | [`Newsletter.send`](/business/nouns/newsletter/send) (`verb:Newsletter.send`) | `newsletter` Newsletter (an id), required: the `$id` step 1 returns; `content` Content (an id), required: the `$id` of the first Content `Content.list` returns | `newsletter` Newsletter |

Returns: the last call answers with `newsletter` and its `action`, whose `status` is `done`, `pending` (waiting on an Approval or a Worker), `failed`, `canceled` or `refused`:

```json
{
  "api": "https://api.sb/leaseline.app",
  "newsletter": {
    "$id": "https://api.sb/leaseline.app/newsletters/newsletter_FLjN3aQujc",
    "$type": "Newsletter",
    "name": "Renewal notes",
    "topic": "renewal-notes",
    "from": "mailbox_93HvOnR17L"
  },
  "action": {
    "$id": "https://api.sb/leaseline.app/actions/act_br07HsG8MG",
    "operation": "Newsletter.send",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/leaseline.app/actions/act_br07HsG8MG"
  }
}
```

Next: offer “Charge $8 a month for the full issue”, or “Import my subscribers from a CSV”.

Calls: `Newsletter.create` → `Newsletter.send`

Ask:

```text
Start a newsletter.
Start a paid newsletter.
Email my subscribers every week.
```

API:

```bash
# Look up the Mailbox: Mailbox.list
FROM=$(curl "https://api.sb/leaseline.app/mailboxes?limit=1" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" | jq -r '.mailboxes[0]["$id"] | split("/") | last')

# 1. Newsletter.create
NEWSLETTER=$(curl -X POST https://api.sb/leaseline.app/newsletters \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Renewal notes","from":"'"$FROM"'","topic":"renewal-notes"}' | jq -r '.newsletter["$id"] | split("/") | last')

# Look up the Content: Content.list
CONTENT=$(curl "https://api.sb/leaseline.app/content?limit=1" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" | jq -r '.content[0]["$id"] | split("/") | last')

# 2. Newsletter.send
IDEMPOTENCY_KEY=$(uuidgen)
curl -X POST https://api.sb/leaseline.app/newsletters/$NEWSLETTER/send \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"'"$CONTENT"'"}'
```

SDK:

```ts
import { $ } from 'startup-builder'

const [from] = await $.Mailbox.list({ limit: 1 })
const newsletter = await $.Newsletter.create({ name: 'Renewal notes', from: from.$id, topic: 'renewal-notes' })
const [content] = await $.Content.list({ limit: 1 })
await $.Newsletter.send({ newsletter: newsletter.$id, content: content.$id })
```

CLI:

```bash
FROM=$(npx startup-builder do Mailbox.list --json '{"limit":1}' | jq -r '.mailboxes[0]["$id"] | split("/") | last')
NEWSLETTER=$(npx startup-builder do Newsletter.create --json '{"name":"Renewal notes","from":"'"$FROM"'","topic":"renewal-notes"}' | jq -r '.newsletter["$id"] | split("/") | last')
CONTENT=$(npx startup-builder do Content.list --json '{"limit":1}' | jq -r '.content[0]["$id"] | split("/") | last')
IDEMPOTENCY_KEY=$(uuidgen)
npx startup-builder do Newsletter.send --json '{"newsletter":"'"$NEWSLETTER"'","content":"'"$CONTENT"'"}' --idempotency-key "$IDEMPOTENCY_KEY"
```

MCP:

```json
{
  "name": "do",
  "arguments": {
    "code": "const [from] = await $.Mailbox.list({ limit: 1 })\nconst newsletter = await $.Newsletter.create({ name: 'Renewal notes', from: from.$id, topic: 'renewal-notes' })\nconst [content] = await $.Content.list({ limit: 1 })\nreturn await $.Newsletter.send({ newsletter: newsletter.$id, content: content.$id })"
  }
}
```

## Change it
- Charge $8 a month for the full issue.
- Import my subscribers from a CSV.
- Send every Monday at 7 a.m.

## Under the hood
- Systems: [Email list](/systems/email-list), [Mailboxes](/systems/mailboxes), [CMS](/systems/cms)
- Nouns: [Newsletter](/business/nouns/newsletter), [Contact](/business/nouns/contact), [Consent](/business/nouns/consent), [Content](/business/nouns/content)
- Events: [`Contact.subscribed`](/business/events/Contact.subscribed), [`Newsletter.sent`](/business/events/Newsletter.sent)

Each signup calls [`Contact.subscribe`](/business/nouns/contact/subscribe), which writes one [Consent](/business/nouns/consent) for the [Newsletter](/business/nouns/newsletter)’s topic. A paid tier is an [Offer](/business/nouns/offer) whose [Entitlement](/business/nouns/entitlement) gates the full issue and the archive.