# Molted Email CLI — Agent Reference

You are integrating with Molted Email, an agent-native email control plane.
The `molted` CLI handles auth, headers, and tenant ID automatically.
All commands output JSON to stdout and errors to stderr.

Install: `npm install -g @molted/cli`

---

## Command Tree

```
molted
├── auth signup|login|init|logout|login-link
│   └── keys list|create|revoke
├── send --to --template --dedupe-key --payload
│   ├── batch --template --recipients|--stdin
│   ├── simulate --to --template
│   ├── simulate-batch --template --recipients
│   └── propose --to [--context]
├── mailboxes create|list|get|update|delete|clone|stats
├── templates create|list|get|add-version|publish|approve|reject|render
├── threads list|get|reply|update|archive|unarchive|trash|restore|delete|followup
├── domains add|list|get|verify|dns-check|remove
├── contacts list|get|sync
├── billing status|setup
├── budget
├── analytics fatigue|velocity|deliverability|segment-check
├── journeys create|list|get|update|add-step|runs|trigger
├── segments create|list|get|update|archive|compute|members|contact
├── outcomes ingest|list|get|dashboard|journey-impact
├── suppressions add|list|remove|add-domain|list-domains|remove-domain
├── consent record|check
├── safety get|update
├── humanizer get|update
├── classify --subject --body
│   └── batch --emails|--stdin
├── next-action --contact
│   └── batch --contacts|--stdin
├── record-inbound --from --to [--subject --body ...]
├── trace <requestId>
└── timeline <requestId>
```

Global option: `--base-url <url>` — override API base URL.

---

## Getting Started

### 1. Sign up

```bash
molted auth signup --name "My Agent" --email agent@example.com --password s3cret
```

Credentials are stored in `~/.molted/credentials.json` automatically.

### 2. Activate billing

```bash
molted billing status
# → { "sendBlocked": true, "actions": ["setup_billing"] }

molted billing setup --plan starter
# → { "url": "https://checkout.stripe.com/..." }
```

Open the URL to complete payment. Sends are blocked until billing is active.

### 3. Send your first email

```bash
molted send \
  --to alice@example.com \
  --template _default \
  --dedupe-key "welcome-alice-1" \
  --payload '{"body": "Hello from my agent!"}'
```

---

## Command Reference

### auth

```bash
molted auth signup --name <n> --email <e> --password <p>   # create account + store creds
molted auth login --email <e> --password <p>               # log in + store creds
molted auth init --key <mm_live_...>                       # init from existing API key
molted auth logout                                         # clear stored creds
molted auth login-link                                     # portal login URL for a human
molted auth keys list                                      # list API keys
molted auth keys create [--label <label>]                  # create a new key
molted auth keys revoke <id>                               # revoke a key
```

### send

```bash
# Single send (required: --to, --template, --dedupe-key, --payload)
molted send --to alice@example.com --template welcome \
  --dedupe-key "welcome-alice-1" --payload '{"name":"Alice"}' \
  [--reason <r>] [--mailbox <id>] [--idempotency-key <k>] [--attachments '<json>']

# Batch send
molted send batch --template welcome \
  --recipients '[{"email":"a@b.com","dedupeKey":"k1","payload":{"name":"A"}}]' \
  [--mailbox <id>] [--stdin]

# Dry-run policy check
molted send simulate --to alice@example.com --template welcome [--dedupe-key <k>] [--mailbox <id>]

# Batch dry-run
molted send simulate-batch --template welcome --recipients '["a@b.com","b@c.com"]'

# AI-generated email proposal
molted send propose --to alice@example.com [--context '{"topic":"renewal"}']
```

### mailboxes

```bash
molted mailboxes create --address agent@yourdomain.com [--display-name "Agent"]
molted mailboxes list
molted mailboxes get <id>
molted mailboxes update <id> [--display-name <n>] [--status active|paused] [--catch-all] [--no-catch-all] [--config '<json>']
molted mailboxes delete <id>
molted mailboxes clone <id> --address clone@yourdomain.com [--display-name "Clone"]
molted mailboxes stats <id> [--period 24h|7d|30d]
```

### templates

```bash
molted templates create --name "Welcome" --slug welcome \
  [--type marketing|transactional (default: marketing)] [--approval-required] \
  [--subject "Hi {{name}}"] [--body "<h1>Hello</h1>"] [--text "Hello"] \
  [--variables '<json>'] [--auto-publish]

molted templates list
molted templates get <id>

molted templates add-version <id> --subject "Hi {{name}}" --body "<h1>Hello</h1>" \
  [--text "Hello"] [--variables '<json>']

molted templates publish <id> [--requested-by <name>]
molted templates approve <approvalId> [--reviewed-by <name>] [--comment "LGTM"]
molted templates reject <approvalId> [--reviewed-by <name>] [--reason "Needs work"]
molted templates render <id> --payload '{"name":"Alice"}'
```

### threads

```bash
molted threads list [--mailbox <id>] [--status open|waiting|resolved|escalated] \
  [--direction inbound|outbound] [--view active|archived|trashed] \
  [--contact <email>] [--limit <n>] [--offset <n>]

molted threads get <id>

# Reply (shorthand with _default template)
molted threads reply <threadId> --body "Thanks for reaching out!"
# Reply (with explicit template)
molted threads reply <threadId> --template-id welcome --payload '{"name":"Alice"}' \
  [--dedupe-key <k>] [--send-reason "followup"]

molted threads update <id> [--status open|waiting|resolved|escalated] \
  [--metadata '<json>'] [--assigned-agent-id <id>]

# Bulk operations (accept multiple IDs)
molted threads archive <id1> <id2> ...
molted threads unarchive <id1> <id2> ...
molted threads trash <id1> <id2> ...
molted threads restore <id1> <id2> ...
molted threads delete <id>          # permanent, must be trashed first

molted threads followup <requestId> --contact-email alice@example.com \
  --delay-hours 24 | --delay-minutes 1440 \
  [--cancel-on-reply] [--trigger-conditions '<json>']
```

### domains

```bash
molted domains add <domain> [--receiving]     # add a custom sending domain
molted domains list
molted domains get <id>                       # includes DNS record status
molted domains verify <id>                    # trigger DNS verification
molted domains dns-check <id>                 # check one-click DNS availability
molted domains remove <id>
```

### contacts

```bash
molted contacts list [--email <email>]
molted contacts get <id>
molted contacts sync --contacts '[{"email":"a@b.com","name":"A"}]'  # or --stdin
```

### billing & budget

```bash
molted billing status       # plan, sendBlocked, hasPaymentMethod
molted billing setup [--plan starter] [--success-url <url>] [--cancel-url <url>]
molted budget               # remaining send quota (monthly/daily/hourly)
```

### analytics

```bash
molted analytics fatigue --contact alice@example.com
# → { "recommendation": "safe_to_send"|"reduce_frequency"|"stop_sending", ... }

molted analytics velocity
molted analytics deliverability [--period 24h|7d|30d]
molted analytics segment-check --contact alice@example.com --segment <id>
```

### journeys

```bash
molted journeys create --name "Onboarding" --trigger-event signup \
  [--trigger-conditions '<json>']
molted journeys list
molted journeys get <id>
molted journeys update <id> [--name <n>] [--status active|paused|archived]
molted journeys add-step <id> --step-order 1 --step-type send --config '{"templateId":"tpl_abc123"}'
molted journeys add-step <id> --step-order 2 --step-type delay --config '{"delayMinutes":1440}'
molted journeys add-step <id> --step-order 3 --step-type branch \
  --config '{"conditions":[{"field":"properties.plan","operator":"eq","value":"pro"}],"onMatch":{"nextStep":4},"onNoMatch":{"nextStep":5}}'
molted journeys add-step <id> --step-order 4 --step-type end
molted journeys runs <id>        # list runs for a journey
molted journeys trigger --event signup --contact a@b.com --properties '{"plan":"pro"}'
```

### segments

```bash
molted segments create --name "Active Users" --filters '<json>'
molted segments list
molted segments get <id>
molted segments update <id> [--name <n>] [--filters '<json>']
molted segments archive <id>
molted segments compute <id>              # recompute membership
molted segments members <id> [--limit <n>] [--offset <n>]
molted segments contact <contactId>       # list segments a contact belongs to
```

### outcomes

```bash
molted outcomes ingest --contact a@b.com --event-type conversion --event-name signup \
  [--revenue 99.99] [--metadata '<json>'] [--occurred-at 2025-01-15]
molted outcomes list [--event-type <t>] [--from <iso>] [--to <iso>]
molted outcomes get <id>
molted outcomes dashboard
molted outcomes journey-impact
```

### suppressions

```bash
molted suppressions add --email a@b.com \
  --reason complaint|hard_bounce|manual_dnc|legal_request|role_account|domain_suppressed|no_engagement \
  --scope tenant|campaign [--campaign-id <id>] [--source <s>] [--expires-at <iso>]
molted suppressions list [--email <email>]
molted suppressions remove <id>

molted suppressions add-domain --domain spam.co [--reason manual_dnc] [--source <s>]
molted suppressions list-domains
molted suppressions remove-domain <domain>
```

### consent

```bash
molted consent record --email a@b.com \
  --type explicit_opt_in|legitimate_interest|contractual|legal_obligation \
  [--source signup-form] [--jurisdiction EU|US-CA] \
  [--granted-at <iso>] [--revoked-at <iso>]

molted consent check --email a@b.com
```

### safety & humanizer

```bash
molted safety get                          # current tenant safety settings
molted safety update --settings '<json>'   # update safety settings

molted humanizer get                       # current humanizer config
molted humanizer update --config '<json>'  # update humanizer config
```

### classify, next-action, record-inbound

```bash
molted classify --subject "Re: Invoice" --body "Please find attached..."
molted classify batch --emails '[{"subject":"Hi","body":"Hello"}]'  # or --stdin

molted next-action --contact alice@example.com
molted next-action batch --contacts '["a@b.com","c@d.com"]'  # or --stdin

molted record-inbound --from alice@example.com --to agent@yourdomain.com \
  [--subject "Re: Hello"] [--body "Thanks!"] [--body-html "<p>Thanks!</p>"] \
  [--in-reply-to <messageId>] [--references <header>] \
  [--provider-message-id <id>] [--mailbox <id>] [--thread <id>]
```

### trace & timeline

```bash
molted trace <requestId>      # full decision trace for a send request
molted timeline <requestId>   # delivery event timeline (sent → delivered → opened)
```

---

## Common Patterns

### Pattern 1: Safe Send (Simulate → Send)

```bash
molted send simulate --to alice@example.com --template welcome
# → check result.status — if "allowed", proceed:
molted send --to alice@example.com --template welcome \
  --dedupe-key "welcome-alice-1" --payload '{"name":"Alice"}'
```

### Pattern 2: Informed Send (Propose → Simulate → Send)

```bash
molted send propose --to alice@example.com --context '{"topic":"renewal"}'
# → returns suggested template + context
molted send simulate --to alice@example.com --template <suggested>
molted send --to alice@example.com --template <suggested> \
  --dedupe-key "renewal-alice-1" --payload '<suggested payload>'
```

### Pattern 3: Send with Follow-up

```bash
molted send --to alice@example.com --template outreach \
  --dedupe-key "outreach-alice-1" --payload '{"name":"Alice"}'
# → note the requestId from the response
molted threads followup <requestId> --contact-email alice@example.com \
  --delay-hours 72 --cancel-on-reply
```

### Pattern 4: Inbound Triage

```bash
molted classify --subject "Re: Invoice" --body "Where is my invoice?"
# → { "intent": "question", "confidence": 0.95 }
molted next-action --contact alice@example.com
# → { "action": "reply", "reason": "..." }
molted threads reply <threadId> --body "Your invoice is attached."
```

### Pattern 5: Batch Outreach

```bash
molted budget
# → check remaining quota
molted send simulate-batch --template promo --recipients '["a@b.com","c@d.com"]'
# → review which recipients are allowed
molted send batch --template promo \
  --recipients '[{"email":"a@b.com","dedupeKey":"promo-a","payload":{"name":"A"}}]'
```

### Pattern 6: Fatigue-Aware Send

```bash
molted analytics fatigue --contact alice@example.com
# → { "recommendation": "safe_to_send" } — proceed
# → { "recommendation": "reduce_frequency" } — delay or skip
# → { "recommendation": "stop_sending" } — do not send
```

### Pattern 7: Journey-Driven Onboarding

```bash
molted templates create --name "Day 1" --slug onboard-day1 \
  --subject "Welcome {{name}}" --body "<h1>Welcome!</h1>" --auto-publish
molted journeys create --name "Onboarding" --trigger-event signup
molted journeys add-step <journeyId> --step-order 1 --step-type send \
  --config '{"templateId":"tpl_abc123"}'  # use the id from templates create, not the slug
molted journeys add-step <journeyId> --step-order 2 --step-type delay \
  --config '{"delayMinutes":1440}'
molted journeys update <journeyId> --status active
molted journeys trigger --event signup --contact a@b.com --properties '{"name":"A"}'
```

### Pattern 8: Full Setup (New Agent)

```bash
# Option A: create a new account
molted auth signup --name "My Agent" --email agent@example.com --password s3cret
# Option B: use an existing API key from the dashboard
molted auth init --key mm_live_your_key_here
molted billing setup --plan starter
# → open checkout URL, complete payment
molted templates create --name "Welcome" --slug welcome \
  --subject "Hi {{name}}" --body "<h1>Hello</h1>" --auto-publish
molted send simulate --to alice@example.com --template welcome
molted send --to alice@example.com --template welcome \
  --dedupe-key "welcome-alice-1" --payload '{"name":"Alice"}'
# Optional: custom domain + mailbox
molted domains add yourdomain.com --receiving
molted domains verify <domainId>
molted mailboxes create --address agent@yourdomain.com
```

---

## Idempotency

The `--dedupe-key` flag guarantees exactly-once semantics:

- First call with a given key: processed normally
- Subsequent calls with the same key: blocked with reason `duplicate`

Use deterministic keys like `{workflow}-{contactId}-{step}` to make retries safe.

---

## Error Handling

- **Exit code 0**: success — JSON result on stdout
- **Exit code 1**: error — JSON error on stderr

A policy-blocked send returns exit code 0 with `status: "blocked"` in the output. The request was valid; policy just didn't allow it. Always inspect the `status` field.

| Status | Meaning |
|--------|---------|
| `sent` | Email queued for delivery |
| `blocked` | Policy denied the send (check `reason`) |
| `duplicate` | Same `dedupeKey` already used |

Common block reasons: `fatigue_limit`, `suppressed`, `no_consent`, `rate_limited`, `trial_not_activated`.

---

## Rate Limits

Per-tenant quotas (configurable by plan):

| Window | Default |
|--------|---------|
| Monthly | Plan-based (Trial: 100, Starter: 3,000, Growth: 10,000) |
| Daily | 10,000 |
| Hourly | 1,000 |

Check current usage with `molted budget` before large batches.
