# Work from the command line

> The minket command line: profiles with live and test keys, sending with attachments, domains, logs and events, webhooks, keys, templates from React Email, inbound mail, contact imports, and any operation with minket api.

Source: https://docs.minket.com/cli/
Updated: 2026-10-29

`minket` drives the platform from a terminal or a CI job. It is built on the [TypeScript SDK](https://docs.minket.com/sdks/), so every POST carries an idempotency key and every error its code and request id.

```sh
pnpm --filter @minket/cli build          # writes apps/cli/dist/bin.mjs
alias minket="node $PWD/apps/cli/dist/bin.mjs"
minket --help
```

## Keys and profiles

`minket login` asks for a key without echoing it and saves it to a profile in `~/.config/minket/config.json` (mode 0600). A `minket_test_…` key goes in the profile's test slot, any other in its live slot, so one profile holds both:

```sh
minket login                                         # profile "default"
minket login --profile shop                          # another profile
minket profiles list                                 # keys shown as minket_live_…k9Qz
minket profiles use shop
minket whoami
```

`whoami` calls `GET /v1/keys/current`, which every key may call, and prints the project, environment, mode and scope of the key in use. Keys are never printed.

The profile is `--profile`, else `MINKET_PROFILE`, else the current one; `--base-url` points a profile at another API address. `MINKET_API_KEY`, `MINKET_TEST_API_KEY` and `MINKET_BASE_URL` win over the file, which is how CI uses it. `--test` on any command uses the test key ([Test mode](https://docs.minket.com/sending/#test-mode)).

## Sending

```sh
minket send --from "Acme <billing@mail.acme.example>" --to jane@example.com \
  --subject "Your receipt" --text "Thanks, Jane." --tag type=receipt

minket send --to jane@example.com --template receipt --var order=10452 --scheduled-at "in 1 hour"

minket send --from billing@mail.acme.example --to jane@example.com --subject "Your report" \
  --html-file report.html --attach report.pdf data.csv

minket send --test --from billing@mail.acme.example --to bounced@minket.test --subject Test --text Test
```

Attachments go inline while they fit in 4 MB together; larger files, up to 25 MB each, go through a presigned upload and are referenced by id. Uploads never carry the API key. `--idempotency-key` makes a send safe to rerun; without it each run is a new email. `--stream`, `--topic`, `--via-mailbox` and `--header name=value` match the fields of [the send request](https://docs.minket.com/sending/).

```sh
minket emails list --status bounced --limit 20
minket emails get <id>
minket emails events <id>                       # the timeline
minket emails reschedule <id> --scheduled-at "tomorrow at 9am"
minket emails cancel <id>
```

## Domains

```sh
minket domains add mail.acme.example --stream transactional
minket domains records <id>                     # the DNS records to create
minket domains records <id> --format zone       # as zone-file lines for a DNS import
minket domains verify <id>
minket domains list
```

## Logs and events

```sh
minket logs tail                                # request logs, then follow
minket logs tail --events --types email.bounced,email.complained
minket logs list --status 422 --error-code validation_error
minket logs get <id>
minket events tail --types email.delivered
minket events get <id>
```

`tail` prints the latest entries, then polls with a `before=<newest id>` cursor and prints anything newer; `--events` follows [the event feed](https://docs.minket.com/events/) beside the request logs, each with its own cursor, merged by time. Ctrl-C stops it.

## Webhooks, keys and suppressions

```sh
minket webhooks list
minket webhooks create https://hooks.acme.example/minket --events email.delivered email.bounced
minket webhooks deliveries <id> --status failed
minket webhooks replay <id> --since 2026-10-24T00:00:00Z
minket webhooks test <id> --type email.delivered

minket keys list
minket keys create --name ci --environment <environment id> --mode live --scope sending_access
minket keys revoke <id>

minket suppressions list --reason hard_bounce
minket suppressions add jane@example.com --stream marketing
minket suppressions remove <id>
```

A new key's token and a new webhook's signing secret are printed once.

## Templates from React Email

```sh
minket templates push receipt.html --alias receipt --subject "Your receipt for {{order}}" --publish
minket templates push emails/receipt.tsx --alias receipt --publish
minket templates list
```

A `.tsx`, `.jsx` or `.js` file is rendered on your machine with `@react-email/render`, `react` and `tsx` from the current project (`pnpm add -D @react-email/render react tsx`), and only the HTML is uploaded. Write `{{variables}}` literally in the JSX. With `--alias`, a template that already has the alias gets a new version; without it, each push makes a new template. See [Build emails from templates](https://docs.minket.com/templates/).

## Inbound mail and contacts

```sh
minket inbound list --to support@inbound.acme.example
minket inbound get <id>                         # headers, verdicts, attachments, text
minket inbound get <id> --html

minket contacts import people.csv --map email=E-mail --map first_name=First --map plan=Plan --wait
minket contacts get jane@example.com
minket contacts list --status unsubscribed
```

An `inbound_read` key is enough for `inbound`. `contacts import` maps columns to `email`, `first_name`, `last_name`, `unsubscribed` or a property key; files up to 4 MB go inline and larger ones (up to 50 MB) through an upload. `--wait` follows the import until it finishes and prints its counts; imports never resubscribe anyone ([Import and export](https://docs.minket.com/audience/#import-and-export)).

## Any operation

`minket api` reaches every operation of the [API reference](https://docs.minket.com/api/), including those without a command of their own (broadcasts, automations, segments, topics, mailboxes, members):

```sh
minket api                                      # every operation, by group
minket api listBroadcasts --query limit=5
minket api sendBroadcast <id> --body '{"scheduled_at": "tomorrow at 9am"}'
minket api createSegment --body @segment.json
cat contact.json | minket api createContact --body -
```

Path parameters are positional, in path order; `--query name=value` repeats; `--body` takes JSON, `@file.json` or `-` for standard input. The CLI checks the operation, its parameters and whether it takes a body before calling, and prints the answer as JSON.

## Output and exit codes

`--json` prints the API's JSON instead of text; `tail` prints one object per line. A command exits 0 on success and 1 on a usage or API error, with the error code, message, validation issues and request id on stderr (as JSON with `--json`):

```txt
error validation_error: Invalid `to` field.
  to.0: Must be a valid email address.
request id: req_019a2b3c-4d5e-7f60-8a9b-0c1d2e3f4a5b
```

`request id` finds the request with `minket logs list` or in the console's Logs page.
