Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
87a1147
Add contacts import and Import History names for CSV imports
thedogwiththedataonit Oct 20, 2026
6bc6526
Keep JSON-body import options; CSV credits per row; pin SDK 07b8a6f
thedogwiththedataonit Oct 20, 2026
5985af2
Resync the OpenAPI spec (route-neutral importId description)
thedogwiththedataonit Oct 20, 2026
0479076
CSV validation is metered per data row; resync the spec
thedogwiththedataonit Oct 20, 2026
5d3b102
Pin the SDK head of typescript-sdk#76
thedogwiththedataonit Oct 20, 2026
98ee571
Merge origin/main into claude/contact-imports; pin the SDK to b73634f…
thedogwiththedataonit Oct 20, 2026
34f22d1
chore(openapi): re-vendor the spec from brew-v2#2194 after main's EMA…
thedogwiththedataonit Oct 20, 2026
18f65e4
Merge published CLI 0.17 baseline into contact imports
thedogwiththedataonit Oct 21, 2026
03aee93
Integrate reviewed template category support into contact imports
thedogwiththedataonit Oct 21, 2026
16f44ff
feat(contacts): import commands print a per-row summary on a terminal
thedogwiththedataonit Oct 21, 2026
0d2b34f
Merge latest terminal import summary
thedogwiththedataonit Oct 21, 2026
7e443f2
Render supported import outcomes from the canonical API
thedogwiththedataonit Oct 21, 2026
66e1d76
Validate imports against the reviewed SDK 13 source baseline
thedogwiththedataonit Oct 21, 2026
0d6b11d
Show completed contact import validation results on terminals
thedogwiththedataonit Oct 21, 2026
bfdbd64
Synchronize final import totals and row diagnostics
thedogwiththedataonit Oct 21, 2026
91c0a76
Merge remote-tracking branch 'origin/main' into review/imports-cli65-…
thedogwiththedataonit Oct 21, 2026
5f61137
Refresh the reviewed SDK import pin after main integration
thedogwiththedataonit Oct 21, 2026
8ce11ee
Clarify CSV validation billing across CLI help and contracts
thedogwiththedataonit Oct 21, 2026
db747ef
chore(openapi): JSON import validate states its submitted-contact met…
thedogwiththedataonit Oct 21, 2026
a4d0b9f
chore(openapi): CSV row numbers skip the header and blank lines
thedogwiththedataonit Oct 21, 2026
613cc4c
build(deps): depend on the published @brew.new/sdk ^13.3.0
thedogwiththedataonit Oct 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,36 @@

## Unreleased

These import changes require `@brew.new/sdk` 13.3.0 or newer, which adds
`contacts.import` and the shared import response.

### Added

- Synchronize email-category and template browse-group contracts with app
revision `9bf2e01f14d8260bdde0825e901a05497b66c70c`. Template reads accept
`--group`, and `--count --group-by group` labels browse groups correctly in
human output. These additions require the matching API deployment.
- **`contacts import`** (`POST /v1/contacts/import`): bulk-import up to 1000
contacts from a JSON file (an array, or `{ "contacts": [...] }`) or stdin as
one batch in Brew's Import History. Takes `--file-name`, `--validate` and
`--consent-source`, and prints the batch's `importId`. A JSON object body
keeps its own `validate`, `consent` and `fileName`; a flag overrides them
only when given.
- `contacts import-csv` names its batch in Import History: `--file-name`, else
a `fileName` in `--input`, else the `--file` name. Both imports return
`importId`.
- On a terminal, `contacts import` and `contacts import-csv` print the API's
submitted total and outcome counts, plus failed rows and warnings with
available row, email and field details. `--json` preserves the API envelope.
CSV skip warnings list the first 100 skipped rows and summarize the rest;
column-wide and aggregate warnings have no row index.
- Completed import deliverability checks show valid, risky, invalid and
unscored counts, plus available persistence counts, in terminal output.

### Changed

- `contacts upsert-many` says what it is for: up to 1000 contacts per call
(its summary said 100) with no Import History entry, for recurring syncs.

## 0.17.0

Expand Down
10 changes: 8 additions & 2 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ JSON response. Do not release these commands with an SDK version that discards
that response.

SDK 13.0.0 preserves the revocation JSON response and is the minimum supported
SDK release for these commands. The dependency and Bun lockfile consume the
published registry artifact; the temporary Git source pin has been removed.
SDK release for these commands. CLI 0.17.0 consumes that published registry
artifact.

For future upgrades, release the SDK first, then update the dependency and
regenerate `bun.lock` from its actual published artifact. Run frozen
Expand All @@ -23,6 +23,12 @@ CLI. A locally packed SDK must not hide dependency failures, and future
lockfile checksums must never be invented. The canvas tests must preserve
`{ revoked: true }`, the `--yes` gate, and one-attempt create/refresh requests.

### Contact Import SDK Minimum

`contacts import` and the `contacts import-csv` naming and row results use
`contacts.import` and the import response from SDK 13.3.0, the minimum this
CLI depends on (`^13.3.0`).

```bash
# on a clean main with CI green
npm version <patch|minor|major> --no-git-tag-version
Expand Down
7 changes: 5 additions & 2 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 27 additions & 6 deletions docs/commands/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!-- GENERATED FILE — do not edit. Regenerate with `bun run docs:commands`. -->

148 commands. Classes: read (always safe), write
149 commands. Classes: read (always safe), write
(mutating, retry-safe), destructive (irreversible — the confirmation
protocol applies: interactive y/N on a TTY, exit 4 + JSON envelope with
a `confirmCommand` otherwise, `--yes` to proceed).
Expand Down Expand Up @@ -35,12 +35,13 @@ a `confirmCommand` otherwise, `--yes` to proceed).
| `brew-cli contacts count` | read | `POST /v1/contacts/search` | Count contacts matching a filter |
| `brew-cli contacts count-by` | read | `POST /v1/contacts/search` | Count contacts per field value, email domain, or signup period (largest group first) |
| `brew-cli contacts upsert` | write | `POST /v1/contacts` | Create or update one contact by email |
| `brew-cli contacts upsert-many` | write | `POST /v1/contacts` | Create or update a batch of contacts (up to 100 per call) |
| `brew-cli contacts upsert-many` | write | `POST /v1/contacts` | Create or update up to 1000 contacts per call, with no Import History entry (for syncs; use contacts import for a batch you want listed) |
| `brew-cli contacts update` | write | `PATCH /v1/contacts/{email}` | Partially update one contact (PATCH; never retried) |
| `brew-cli contacts delete` | destructive | `DELETE /v1/contacts/{email}` | Delete one contact by email (idempotent) |
| `brew-cli contacts delete-many` | destructive | `POST /v1/contacts/batch-delete` | Delete up to 1000 contacts by email |
| `brew-cli contacts validate` | write ($) | `POST /v1/contacts/validate` | Batch-validate email deliverability (no contacts created) |
| `brew-cli contacts import-csv` | write | `POST /v1/contacts/import-csv` | Bulk-import contacts from a CSV file or stdin (free; --validate costs 2 credits per address) |
| `brew-cli contacts import` | write | `POST /v1/contacts/import` | Bulk-import up to 1000 contacts from a JSON file or stdin as one Import History batch (free; --validate costs 2 credits per address) |
| `brew-cli contacts import-csv` | write | `POST /v1/contacts/import-csv` | Bulk-import contacts from a CSV file or stdin as one Import History batch (free; validation charged separately) |
| `brew-cli fields list` | read | `GET /v1/fields` | List custom contact fields |
| `brew-cli fields get` | read | `GET /v1/fields/{fieldName}` | Fetch one contact field definition by name — the bare row |
| `brew-cli fields create` | write | `POST /v1/fields` | Create a custom contact field |
Expand Down Expand Up @@ -374,7 +375,7 @@ brew-cli contacts upsert --email j@x.com --custom plan=pro --custom seats=4

### brew-cli contacts upsert-many

Create or update a batch of contacts (up to 100 per call)
Create or update up to 1000 contacts per call, with no Import History entry (for syncs; use contacts import for a batch you want listed)

- Route: `POST /v1/contacts`
- Class: write
Expand Down Expand Up @@ -451,17 +452,37 @@ brew-cli contacts validate --emails jane@example.com bob@example.com
brew-cli contacts validate --input '{"emails":["jane@example.com"]}'
```

### brew-cli contacts import

Bulk-import up to 1000 contacts from a JSON file or stdin as one Import History batch (free; --validate costs 2 credits per address)

- Route: `POST /v1/contacts/import`
- Class: write
- SDK: `brew.contacts.import(...)`
- `--file <path>` — JSON file of contacts (an array, or { "contacts": [...] }), or - for stdin
- `--file-name <name>` — Name the batch in Brew's Import History (default: the --file name)
- `--validate` — Deliverability-check every imported address (2 credits per address)
- `--consent-source <source>` — Default marketing consent record for rows without their own: api, form or import
- `--input <json>` — Full JSON request body, or - to read stdin (flags override it)
- `--idempotency-key <key>` — Idempotency-Key for safe retries (auto-generated otherwise)

```bash
brew-cli contacts import --file contacts.json --consent-source import
cat contacts.json | brew-cli contacts import --file - --file-name crm-export.json
```

### brew-cli contacts import-csv

Bulk-import contacts from a CSV file or stdin (free; --validate costs 2 credits per address)
Bulk-import contacts from a CSV file or stdin as one Import History batch (free; validation charged separately)

- Route: `POST /v1/contacts/import-csv`
- Class: write
- SDK: `brew.contacts.importCsv(...)`
- `--file <path>` — CSV file to import, or - for stdin (or csv in --input)
- `--file-name <name>` — Name the batch in Brew's Import History (default: the --file name)
- `--mapping <pairs...>` — Column mapping csvColumn=fieldName, repeatable
- `--date-order <order>` — month_first or day_first: how to read dates like 03/04/2026 (a day over 12 in the column wins; default month-first, with a DATE_ORDER_ASSUMED warning)
- `--validate` — Deliverability-check every imported address (2 credits per address)
- `--validate` — Deliverability checks: up to 100 submitted CSV data rows cost 2 credits/row inline; larger files use background checks when needed, charged per address
- `--consent-source <source>` — Stamp a marketing consent record on every row: api, form or import (sets the source of a record given in --input)
- `--input <json>` — Full JSON request body, or - to read stdin (flags override it)
- `--idempotency-key <key>` — Idempotency-Key for safe retries (auto-generated otherwise)
Expand Down
Loading
Loading