minket drives the platform from a terminal or a CI job. It is built on the TypeScript SDK, so every POST carries an idempotency key and every error its code and request id.

Shell
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:

Shell
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).

Sending

Shell
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.

Shell
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

Shell
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

Shell
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 beside the request logs, each with its own cursor, merged by time. Ctrl-C stops it.

Webhooks, keys and suppressions

Shell
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

Shell
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.

Inbound mail and contacts

Shell
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).

Any operation

minket api reaches every operation of the API reference, including those without a command of their own (broadcasts, automations, segments, topics, mailboxes, members):

Shell
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):

Text
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.

Updated